C# 如果整个消息不适合TCP中的缓冲区,如何确保接收到它?

C# 如果整个消息不适合TCP中的缓冲区,如何确保接收到它?,c#,.net,networking,tcp,tcpclient,C#,.net,Networking,Tcp,Tcpclient,我最近开始在C中使用TCP。我现在希望客户端接收服务器发送的数据 我知道客户不能保证一次收到所有数据。如果发送的数据的大小大于客户端缓冲区的大小,则数据将分部分发送。所以我的问题是:如何将所有接收到的数据存储在字节数组中,然后在接收到所有数据后将其转换为实际消息 我已经将缓冲区大小设置为1,这样可以看到当所有发送的数据都不适合缓冲区时会发生什么。以下是我在Client.cs中调用stream.BeginRead的方法: // Deliberately setting the buffer siz

我最近开始在C中使用TCP。我现在希望客户端接收服务器发送的数据

我知道客户不能保证一次收到所有数据。如果发送的数据的大小大于客户端缓冲区的大小,则数据将分部分发送。所以我的问题是:如何将所有接收到的数据存储在字节数组中,然后在接收到所有数据后将其转换为实际消息

我已经将缓冲区大小设置为1,这样可以看到当所有发送的数据都不适合缓冲区时会发生什么。以下是我在Client.cs中调用stream.BeginRead的方法:

// Deliberately setting the buffer size to 1, to simulate what happens when the message doesn't fit in the buffer.
int bufferSize = 1;
byte[] receiveBuffer;

private void ConnectCallback(IAsyncResult result)
{
    client.EndConnect(result);

    Console.WriteLine("Connected to server.");

    stream = client.GetStream();

    // At this point, the client is connected, and we're expecting a message: "Welcome!"
    receiveBuffer = new byte[bufferSize];
    stream.BeginRead(receiveBuffer, 0, receiveBuffer.Length, new AsyncCallback(ReadCallback), stream);
}

private void ReadCallback(IAsyncResult result)
{
    int bytesLength = stream.EndRead(result);

    // Should be "Welcome!". But of course it's "W", because the bufferSize is 1.
    string message = Encoding.UTF8.GetString(receiveBuffer, 0, bytesLength);

    Console.WriteLine("Received message: {0}", receivedMessage);

    // Reset the buffer and begin reading a new message, which will be "e".
    // However, I want the whole message ("Welcome!") in one byte array.
    receiveBuffer = new byte[bufferSize];
    stream.BeginRead(receiveBuffer, 0, receiveBuffer.Length, ReadCallback, null);
}
这是发送欢迎消息时的输出:

Connected to server.
Received message: W
Received message: e
Received message: l
Received message: c
Received message: o
Received message: m
Received message: e
Received message: !
我是否应该临时存储数据,直到整个消息到达,然后将其转换为字符串

后续问题:如果两条消息紧跟在一起发送,例如欢迎!那你叫什么名字?那么我如何区分这两条信息呢

我是否应该临时存储数据,直到整个消息到达,然后将其转换为字符串

是的,没错

后续问题:如果两条消息紧跟在一起发送,例如欢迎!那你叫什么名字?那么我如何区分这两条信息呢


一般的方法是在消息本身之前发送消息的长度。这样,接收端将知道何时收到完整的包。

正如500-内部服务器错误已经指出的那样,您使用了一个缓冲区。下面是一些代码示例: 接收:

while (true) //you should use a bool variable here to stop this on disconnect.
                {
                    byte[] bytes;

                    bytes = ReadNBytes(ns, 4);
                    //read out the length field we know is there, because the server always sends it.
                    int msgLenth = BitConverter.ToInt32(bytes, 0);
                    bytes = ReadNBytes(ns, msgLenth);
                    //working with the buffer...
                    if (bytes.Length > 0)
                    {
                        try
                        {
                            //do stuff here. bytes contains your complete message.
                        }
                        catch (Exception e) { Log(e.Message); }                            
                    }
                }


public static byte[] ReadNBytes(NetworkStream stream, int n)
    {
        byte[] buffer = new byte[n];
        try
        {
            int bytesRead = 0;

            int chunk;
            while (bytesRead < n)
            {
                chunk = stream.Read(buffer, (int)bytesRead, buffer.Length - (int)bytesRead);
                if (chunk == 0)
                {
                    // error out
                    Log("Unexpected disconnect");
                    stream.Close();
                }
                bytesRead += chunk;
            }
        }
        catch (Exception e) { Log(e.Message); }

        return buffer;
    }

我希望这有帮助

我应该去临时商店吗。。。。对如果愿意,还可以在字符串/数据包的前面加上其长度。如果有两条消息。。。。你不能。你需要一个协议。您可以在每条消息后使用分隔符,例如强制换行符。如果您使用数据包大小作为前缀,则还可以使用它来区分数据包。通常不需要重新发明轮子,有许多现成的协议和库可以做到这一点。提示:您正在发送/接收消息…只是为了澄清-即使客户机的缓冲区比数据大,也不能保证所有数据都能一次收到。这实际上取决于网络如何缓冲数据,而不一定是代码中定义的缓冲区。MSDN states NetworkStream.Read-此方法将尽可能多的可用数据读取到缓冲区参数中,并返回成功读取的字节数。您总是希望检查实际读取的字节数。此外,如果有帮助,您正在研究的主题称为“TCP消息帧”。本页有一些基本想法:
public static void SendObject(NetworkStream ns, byte[] data)
    {
        byte[] lengthBuffer = BitConverter.GetBytes(data.Length);
        ns.Write(lengthBuffer, 0, lengthBuffer.Length);
        ns.Write(data, 0, data.Length);
    }