简体   繁体   中英

Sending some constraints to client from server in C#

I have created a simple server using socket programming in C# which will receive a file from the client side. My sample code segment is given below.

I want to add some restrictions. I want to make a limit on the file size (such as 4 KB or 2 KB) and allowable file formats (such as .doc, .txt, .cpp, etc.) which will be sent to the client as soon as the client connects to the server so that the client can send files accordingly. How will I do that?

Sample code segment:

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Text;

namespace FileTransfer
{
    class Program
    {
        static void Main(string[] args)
        {
            // Listen on port 1234

            TcpListener tcpListener = new TcpListener(IPAddress.Any, 1234);
            tcpListener.Start();

            Console.WriteLine("Server started");

            //Infinite loop to connect to new clients
            while (true)
            {
                // Accept a TcpClient
                TcpClient tcpClient = tcpListener.AcceptTcpClient();
                                Console.WriteLine("Connected to client");
                byte[] data = new byte[1024];
                NetworkStream ns = tcpClient.GetStream();
                int recv = ns.Read(data, 0, data.Length);
                StreamReader reader = new StreamReader(tcpClient.GetStream());

               //Will add some lines to add restrictions...

            }
        }
    }
}

Which additional lines will I have to add to the code to send the restrictions to client?

Basically I think mainly you need two things:

  • define application protocol as suggested in other answer

  • and handle partial read/writes

For handling partial reads (not sure how much such function is needed for write ) you may use function like below :

public static void ReadWholeArray (Stream stream, byte[] data)
{
    int offset=0;
    int remaining = data.Length;
    while (remaining > 0)
    {
        int read = stream.Read(data, offset, remaining);
        if (read <= 0)
            throw new EndOfStreamException 
                (String.Format("End of stream reached with {0} bytes left to read", remaining));
        remaining -= read;
        offset += read;
    }
}

Thing is traditional Stream.Read() doesn't guarantee to read as many bytes as you told it, this method on the other hand, will ensure to have read as many bytes as specified in data.Length parameter. So you can use such function to implement the desired application protocol instead.

Some relevant information about such application protocols you will find here too


Ok this is for example how the server could send file length limit and the file extension:

// Send string
string ext = ".txt";
byte [] textBytes = Encoding.ASCII.GetBytes(ext);
ns.Write(textBytes, 0, textBytes.Length); 

// Now, send integer - the file length limit parameter
int limit = 333;
byte[] intBytes = BitConverter.GetBytes(limit);
ns.Write(intBytes, 0, intBytes.Length); // send integer - mind the endianness

But you will still need some kind of protocol otherwise you should let client read the "full" stream and parse these data later somehow, which isn't trivial if the data doesn't have fixed length etc - otherwise how will the client distinguish which part of the message is text, which integer?

You seem to be making the classical socket mistake. The given code and explanation seem to assume sockets handle in messages. They don't . When used this way, you're using streaming internet sockets , which provide a stream, not messages .

You don't show any code that does the actual sending, so I'm guessing that you just pump a file's data to the other side and close the connection. How else will you know you've successfully transferred an entire file?

This set of rules that client and server have to follow in order to usefully exchange data through sockets is called an application protocol . You will have to have one, otherwise you'll just be sending data to $deity knows where, and you'll have no control over it at all. This means server nor client will know what's going on, they'll just be sending and receiving data and hoping all goes well. So there's not "a few lines" you have to add to your code, you'll have to restructure it entirely.

There are many ways to define an application protocol and many options to choose from, so I'm going to show you an arbitrary one: a textual explanation of messages that are prefixed with an ID and a payload length (if applicable), both in unspecified numeric variables. You could choose little-endian four-byte unsigned integers, for example.

Messages in this format are known as "Type/Length/Value" or TLV . So we define these messages:

ID  Name         Direction         Description                    Payload
1   ServerHello  Server -> Client  The server sends this message  None. 
                                   to every connecting client.    Or maybe server or 
                                                                  protocol version.
2   MaxUpload    Server -> Client  Sent after the ServerHello.    Maximum upload size 
                                                                  in bytes.
3   AllowedExts  Server -> Client  Allowed upload extensions,     The allowed extensions. 
                                   comma-separated. Sent after 
                                   MaxUpload message.
10  IncomingFile Client -> Server  There's a file coming.         The file name.
11  FileUpload   Client -> Server  The file to upload.            The file data.
                                   Sent after IncomingFile.

Now all that's required is to implement this application protocol in server and client and you're done.

You also have to decide what to do if a client or server doesn't adhere to the prototol. It can for example send a message that you can't parse, an unknown message ID, a message length that you don't want to support, an out-of-order message (FileUpload before IncomingFile) or a message that isn't conform the messages sent earlier, like a client uploading a larger file than the server said it would accept or an invalid extension. You also have to think about "acknowledgement" or response messages, like the server telling the client "OK, go ahead, send the next message".

All in all, this is a very broad question and not answered easily. I tried to address that in my comment to your question, which got removed. So here you have your answer.

You can learn more about this on the web, for example Beej's Guide to Network Programming as linked to by Giorgi (be sure to read the entire guide) and Stephen Cleary's blog .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM