TCP服务器接收的数据超出预期

时间:2015-07-21 09:29:50

标签: c# tcp asyncsocket qtcpsocket

我有一个服务器客户端应用程序,其中客户端将图像数据流式传输到服务器。我有以下结构:

客户端:

private void SerializeAndSendMessage(Message msg) {
        BinaryFormatter formatter = new BinaryFormatter();
        MemoryStream stream = new MemoryStream();
        formatter.Serialize(stream, msg);
        byte[] buffer = stream.ToArray();

        if (clientSocket != null)
        {
            if (clientSocket.Connected)
            {
                clientSocket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, SendCallback, null);
            }
        }
    }

private void SendCallback(IAsyncResult ar) {
        try
        {
            clientSocket.EndSend(ar);
            Debug.WriteLine("Message sent.");
        }
        catch (Exception ex)
        {
            //
        }
    }

服务器:

  private void ReceiveCallback(IAsyncResult ar)
    {
        try
        {
            int received = clientSocket.EndReceive(ar);
            Array.Resize(ref buffer, received);
            BinaryFormatter formatter = new BinaryFormatter();

            MemoryStream stream = new MemoryStream(buffer);

            object obj = null;
            stream.Position = 0;
            try
            {
                obj = formatter.Deserialize(stream);
            }
            catch (Exception ex )
            {
               //
            }

            // processing data

            Array.Resize(ref buffer, clientSocket.ReceiveBufferSize);
            clientSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReceiveCallback, null);
        }
        catch (Exception ex)
        {
            //
        }
    }

我期待发生的事情:

  1. 服务器开始接受来自客户端的数据
  2. 客户端发送大小为X的数据
  3. 服务器接收大小为X的数据并开始处理
  4. 客户端仍然在此期间发送数据
  5. 服务器未收到此数据
  6. 服务器已完成处理收到的数据,现在开始从客户端
  7. 接收
  8. 转到2
  9. 发生了什么:

    1. 服务器开始接受来自客户端的数据
    2. 客户端发送大小为X的数据
    3. 服务器接收大小为X的数据并开始处理
    4. 客户端仍然在此期间发送数据
    5. 服务器未收到此数据
    6. 服务器已完成处理收到的数据,现在开始从客户端
    7. 接收
    8. 客户端发送大小为X的第N个数据包
    9. 服务器接收大小为M * X
    10. 的数据

      这显然会导致服务器上的缓冲区填满,并且无法反序列化发送的包。我错过了什么?我可以做些什么来实现上述工作?

1 个答案:

答案 0 :(得分:0)

TCP是一种流媒体协议。如果你在每个客户端之后在客户端进行多次发送操作,TCP会在尝试填充mtu时将它们组合成一个段。

如果mtu已满或者连续50ms计时器过去,或者客户端本身必须确认从服务器收到的数据包,TCP将发送。

TCP是一种非常复杂的协议。那里还有一个计算窗口大小的算法。此窗口大小也会影响客户端接收的段的大小。

底线是因为TCP是流协议,没有通过套接字接收的数据包的概念。您会收到任意数量的字节,您必须自己附加到某种接收缓冲区,具体取决于您正在执行的操作。如果您需要数据包,则必须使用长度字段预先添加您发送的数据,并在服务器上考虑长度。这当然使代码复杂化。或者,如果您想保持简单,只需使用UDP即可。 UDP确实支持数据包,如果数据包没有在某处丢失,你发送的内容将在接收器上以相同的大小接收。 但UDP不可靠,数据包可能会丢失。 TCP是可靠的,是面向连接的,但更复杂。

一般来说,套接字编程不是初学者话题。