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