我有一个服务器客户端应用程序,其中一个客户端正在将图像数据流传输到服务器。我有以下结构:
客户:
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/