TCP socket.receive()似乎丢弃数据包

时间:2014-03-30 16:38:29

标签: c# sockets tcp network-programming

我正在使用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);
            }

然后从客户端发送两条消息,然后释放断点。

之前有没有人遇到过这个问题?

2 个答案:

答案 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