c#套接字:客户端接收大缓冲区时没有接收到所有字节

本文关键字:字节 套接字 客户 客户端 端接 缓冲区 | 更新日期: 2023-09-27 18:03:30

所以当服务器发送小于16384字节时,客户端接收所有数据没有问题。但是一旦服务器发送的数据超过这个数,客户端就会收到奇怪的数据,比如6140。它并不总是这样做,但它大多数时候都这样做,但它经常这样做。它很少接收到完整的16384字节。

起初我认为连接只是花了很长时间才发送完整的金额,所以我将接收超时设置为30秒(30000毫秒)。这解决不了任何问题。每次我接收数据时,我都使用一个新的字节数组,这样它就不会被另一个BeginRecieve()覆盖。

我唯一能想到的是硬件(计算机)不能在内存中保存这些大量的字节,因此截断缓冲区。我有很多代码,但这是基本的东西:

服务器代码(只是其中的一部分):

private void RecieveCallBack(IAsyncResult ar)
{
    Socket client = (Socket)ar.AsyncState;
    try
    {
        int len = client.EndReceive(ar);
        byte[] tempBuffer = new byte[len];
        Array.Copy(buffer, tempBuffer, len);
        object RequestObject = GetRequestObject(tempBuffer); // just deserializes the buffer
        byte[] response = GetResponseFromObject(RequestObject, client); // creates a buffer to return to the client
        client.BeginSend(response, 0, response.Length, SocketFlags.None, new AsyncCallback(SendCallBack), client);
    }
    catch (Exception)
    {
        Program.Log("Client disconnected");
        client.Close();
        clientSockets.Remove(client);
        Program.UpdateClientCount(clientSockets.Count);
    }
}
private void SendCallBack(IAsyncResult ar)
{
    Socket client = (Socket)ar.AsyncState;
    int sent = client.EndSend(ar);
    Program.Log(sent); // log shows that server sent 16384 bytes
    try
    {
        client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(RecieveCallBack), client);
    }
    catch (Exception e)
    {
        Program.Log(e.Message);
    }
}

客户端代码(只是一部分):

static void SendRequest(object obj)
{
    byte[] buffer = SerializeObject(obj);
    try
    {
        serverSockect.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(SendCallBack), null);
    }
    catch // the send failed
    {
        serverSockect.Close();
        ConnectedToServer = false;
    }
}
static Queue<byte[]> buffers = new Queue<byte[]>();
static private void SendCallBack(IAsyncResult ar)
{
    serverSockect.EndSend(ar);
    try
    {
        // Create a new buffer for each new BeginRecieve.
        // If one global buffer was used, then it might get overwritten by
        // a second request when the first request hasn't yet been completed.
        byte[] buffer = new byte[16384];
        buffers.Enqueue(buffer);
        serverSockect.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(RecieveCallBack), null);
    }
    catch // the recieve failed
    {
        serverSockect.Close();
        ConnectedToServer = false;
    }
 }
static private void RecieveCallBack(IAsyncResult ar)
{
    byte[] buffer = buffers.Dequeue();
    int len = serverSockect.EndReceive(ar); // len is usually some weird number
    byte[] tempBuffer = new byte[len];
    Array.Copy(buffer, tempBuffer, len);
    object returnObj = GetResponseObject(tempBuffer);
    HandleResponse(returnObj);
}

c#套接字:客户端接收大缓冲区时没有接收到所有字节

正如BugFinder在评论中已经提到的,TCP流可以分成多个数据包。数据包将按照正确的顺序被接收,但是您不能确定缓冲区中是否包含完整的消息。所以在你的receive方法中,你必须将接收到的数据组合起来,直到你得到一个完整的消息。

另一方面,短消息可以组合成一个包。这两者的混合也是可能的(数据包1包含消息1的第一部分,数据包2包含消息1的第2部分和消息2的第1部分,数据包3包含消息2的第2部分)。因此,您需要一个可以解析以识别消息结尾的协议。

如果您已经序列化了对象,最好的方法是在开始时提供序列化对象的长度。但是,如果没有接收到长度的完整数据,请确保能够正确处理数据。在最坏的情况下,每个字节都可能在一个单独的数据包中!