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

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)
        {
            //
        }
    }

我期望发生的事情:
服务器开始接受来自客户端的数据
客户端发送大小为X的数据
服务器接收大小为X的数据并开始处理它
同时客户端仍在发送数据
服务器未接收此数据
服务器已完成对接收到的数据的处理,现在开始从客户端接收
转到2
发生了什么事:
服务器开始接受来自客户端的数据
客户端发送大小为X的数据
服务器接收大小为X的数据并开始处理它
同时客户端仍在发送数据
服务器未接收此数据
服务器已完成对接收到的数据的处理,现在开始从客户端接收
客户端发送大小为x的第n个数据包
服务器接收大小为m*x的数据
这显然会导致服务器上的缓冲区填满,并且无法对发送的包进行反序列化。我错过了什么?我能做些什么来实现上面描述的工作?

最佳答案

TCP是一种流协议。如果在客户端执行多次发送操作,TCP将在尝试填充到MTU时将它们合并到一个段中。
如果mtu已满或连续50ms计时器超时,或者如果客户端自身必须确认从服务器接收到的数据包,则tcp将发送。
tcp是一个非常复杂的协议。这里还有一个计算窗口大小的算法。此外,此窗口大小还影响在客户端接收的段的大小。
归根结底,因为TCP是流协议,所以没有通过套接字接收数据包的概念。您将收到任意数量的字节,您必须根据所做的操作自行将其附加到某种接收缓冲区中。如果您需要数据包,那么您必须在发送的数据前面加上一个长度字段,并在服务器上考虑长度。这当然会使代码复杂化。或者如果你想保持简单,只需使用udp。udp确实支持数据包,如果数据包没有在某个地方丢失,那么您发送的数据包将在接收端以相同大小接收。
但是udp不可靠,包可能丢失。tcp是可靠的,是面向连接的,但是更复杂。
一般来说,socket编程不是一个初学者的话题。

关于c# - TCP服务器接收的数据超出预期,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31535262/

10-12 02:11
查看更多