如何确定从客户端到服务器(Socket)的文件传输(数据)的结束

时间:2012-10-16 17:16:01

标签: c# sockets client-server

简单的情况:

Socket上的客户端以格式byte []向服务器发送文件(数据)的片段(例如,256字节)。服务器异步接收数据。 如何确定文件(数据)何时完全传输? (服务器端)

这是服务器端负责接收数据的代码

public static void ReadCallback(IAsyncResult ar)
{
        String content = String.Empty;

        // Retrieve the state object and the handler socket
        // from the asynchronous state object.
        StateObject state = (StateObject)ar.AsyncState;
        Socket handler = state.workSocket;


        // Read data from the client socket. 
        int bytesRead = handler.EndReceive(ar);

        if (bytesRead > 0)
        {

            BinaryWriter writer = new BinaryWriter(File.Open(@"D:\test.png", FileMode.Append));

            writer.Write(state.buffer, 0, bytesRead);
            writer.Close();

            // All the data has been read from the 
            // client. Display it on the console.
            Console.WriteLine("Read {0} bytes from socket!",
                bytesRead);

            handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                new AsyncCallback(ReadCallback), state);
        }
}

是否有一种方法可以让一些人跟随?

if (bytesRead > 0)
{

     ....
     if(state.buffer!=end of receive)
     {
     handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
         new AsyncCallback(ReadCallback), state);
     }

}

或者,我可以尝试向此byte[]对象添加一些信息(例如,带有<EOF>标记的某些字符串) 但我必须分析每一步的信息。 我可以做这个检查更简单,怎么做?或者用另一种方式......

1 个答案:

答案 0 :(得分:0)

唯一的方法是在每条消息前面发送一个标题(特定大小)。因此,每条消息应包含标题和正文。数据流应如下所示:

[HEADER] [BODY] [HEADER] [一些更大的身体] [HEADER] [一些额外的大身体]

正如我所说,标题应该是特定的大小,并且应该包含一些自定义服务字段,包括消息的主体大小(以字节为单位)。在您的情况下,标头只能包含主体大小,即int值(4个字节)。接收过程应如下所示:

  1. 接收4个字节(标题);
  2. 从标头中检索主体大小(只需将标头转换为int);
  3. 接收标头中指定的字节数(即接收消息体);
  4. 处理邮件正文;
  5. 转到1.
  6. 我知道,对你来说这似乎很复杂,但这是常见的做法。但您可以使用Rx library来简化代码。在为socket实现一些扩展方法之后(WhenReadExact,可以通过Internet轻松找到实现,例如here),代码将如下所示:

    var whenFileReceived = from header in socket.WhenReadExact(4)
                           let bodySize = BitConverter.ToInt32(header)
                           from body in socket.WhenReadExact(bodySize)
                           select body;
    
    whenFileReceived.Subscribe(
        file =>
        {
            // Handle file here
        });