我正在使用C#进行客户端 - 服务器应用。它们之间的通信是使用TCP套接字。服务器侦听特定端口以获取收入客户端连接。新客户端到达后,他的套接字将保存在套接字列表中。我定义每个新的客户端套接字接收超时为1毫秒。要从客户端套接字接收而不阻塞我的服务器,我使用这样的线程池:
private void CheckForData(object clientSocket)
{
Socket client = (Socket)clientSocket;
byte[] data = new byte[client.ReceiveBufferSize];
try
{
int dataLength = client.Receive(data);
if (dataLength == 0)// means client disconnected
{
throw (new SocketException(10054));
}
else if (DataReceivedEvent != null)
{
string RemoteIP = ((IPEndPoint)client.RemoteEndPoint).Address.ToString();
int RemotePort = ((IPEndPoint)client.RemoteEndPoint).Port;
Console.WriteLine("SERVER GOT NEW MSG!");
DataReceivedEvent(data, new IPEndPoint(IPAddress.Parse(RemoteIP), RemotePort));
}
ThreadPool.QueueUserWorkItem(new WaitCallback(CheckForData), client);
}
catch (SocketException e)
{
if (e.ErrorCode == 10060)//recieve timeout
{
ThreadPool.QueueUserWorkItem(new WaitCallback(CheckForData), client);
}
else if(e.ErrorCode==10054)//client disconnected
{
if (ConnectionLostEvent != null)
{
ConnectionLostEvent(((IPEndPoint)client.RemoteEndPoint).Address.ToString());
DisconnectClient(((IPEndPoint)client.RemoteEndPoint).Address.ToString());
Console.WriteLine("client forcibly disconected");
}
}
}
}
我的问题是,当有时客户端一个接一个地发送2条消息时,服务器不会收到第二条消息。我检查了wireshark,它显示两条消息都已收到并且还得到了ACK。
当我在这里提出断点时,我可以强制解决这个问题:
if (e.ErrorCode == 10060)//recieve timeout
{
ThreadPool.QueueUserWorkItem(new WaitCallback(CheckForData), client);
}
然后从客户端发送两条消息,然后释放断点。
之前有没有人遇到过这个问题?
答案 0 :(得分:2)
我的问题是,有时客户端一个接一个地发送2条消息,服务器没有收到第二条消息
我认为 接收第二条消息的可能性更大,但只需一次Receive
次呼叫。
不要忘记TCP是流协议 - 仅仅因为数据被分解为较低级别的数据包并不意味着一个“发送”对应于一个“接收”。 (由于单个Send
呼叫可能会发送多个数据包,或者可能会将多个Send
呼叫合并到一个数据包中等等。)
通常更容易使用TcpClient
之类的内容,并将其NetworkStream
视为流。如果要在TCP之上对“消息”进行分层,则需要自己进行 - 例如,为每条消息添加大小(以字节为单位),以便您知道何时完成了一条消息的接收并且可以在下一条消息开始。如果你想异步处理这个问题,我建议你唱C#5和async / await。它比明确处理线程池更简单。
答案 1 :(得分:1)
消息框架是您需要做的。这里:http://blog.stephencleary.com/2009/04/message-framing.html
如果您不熟悉套接字编程,建议您阅读这些常见问题http://blog.stephencleary.com/2009/04/tcpip-net-sockets-faq.html