C#async开始接收回叫方法错过了一些数据包

时间:2013-12-16 11:45:13

标签: c# sockets asynchronous

我从客户端向使用BeginReceive

监听的服务器发送2个连续数据包

如果我在调试模式下运行客户端并慢慢发送下一个数据包,服务器总是收到第一个数据包但不接收另一个数据包。

这是我发送功能的片段

if (soc.Connected)
{
    byte[] byData = new byte[System.Text.Encoding.ASCII.GetByteCount("Hi")];
    byData = System.Text.Encoding.ASCII.GetBytes("Hi");
    soc.Send(BitConverter.GetBytes(byData.Length));
    soc.Send(byData);
}

这是我的回调函数,位于我的服务器内部:

 private void Recieve(IAsyncResult iar)
 {
    int j = 0;

    Socket server_conn = (Socket)iar.AsyncState;
    server_conn.EndReceive(iar);

    if (!SocketConnected(server_conn))
    {   
        server_conn.Close();
        return;
    }

    if (g_bmsg.Length != 0)
    {
        logthis(server_conn.RemoteEndPoint.ToString() + ": " + Encoding.ASCII.GetString(g_bmsg, 0, g_bmsg.Length));
    }

    //Find out who sent this
    foreach (ClientData cls in clientlist)
    {
        if (server_conn.RemoteEndPoint == cls.clientsock.RemoteEndPoint)
        {
            j = cls.index;
            break;
        }
    }
     server_conn.BeginReceive(g_bmsg, 0, g_bmsg.Length, SocketFlags.None, new AsyncCallback(Recieve), server_conn);
}

1 个答案:

答案 0 :(得分:1)

使用TCP / IP套接字(或几乎任何通信层)时,您很少能保证您要发送的整个邮件将包含在一个数据包中。

这意味着您应始终保留自己的FIFO缓冲区,并按顺序解析它。

这是一般的想法:

// fifo queue (for background thread parsing, make sure it's thread safe)
private readonly ConcurrentQueue<byte> _commQueue = new ConcurrentQueue<byte>();

Receive方法中,您应该简单地将数据排入FIFO:

private void Receive(IAsyncResult iar)
{
    Socket server_conn = (Socket)iar.AsyncState;

    // check how many bytes we actually received
    var numBytesReceived = server_conn.EndReceive(iar);

    if (!SocketConnected(server_conn))
    {   
        server_conn.Close();
        return;
    }

    // get the received data from the buffer
    if (numBytesReceived > 0)
    {
        for (int i = 0; i < numBytesReceived; i++)
            _commQueue.Enqueue(g_bmsg[i]);

        // signal the parser to continue parsing        
        NotifyNewDataReceived();
    }

    // continue receiving
    server_conn.BeginReceive(g_bmsg, 0, g_bmsg.Length, SocketFlags.None, new AsyncCallback(Recieve), server_conn);
}