这是documented in the Receive() method,强调我的:
Receive 方法将数据读入缓冲区参数并返回成功读取的字节数。您可以从面向连接的套接字和无连接套接字调用 Receive。
忽略返回值时,您将不知道缓冲区的哪一部分实际包含相关数据。根据所使用的协议,您可能会或可能不会提前知道内容长度。一些协议提供此长度,其他协议在完成后关闭连接,还有一些协议可以使用消息边界。
您必须将接收到的数据保存在另一个缓冲区中,并在没有更多可用或预期数据时返回或输出整个消息缓冲区。可以这样完成:
int BufferSize = 1024;
using (var socket = new Socket(SocketType.Stream, ProtocolType.IP))
{
socket.Connect(IPAddress.Parse("127.0.0.1"), 5000);
byte[] buffer = new byte[BufferSize];
string message = "";
int bytesReceived;
do
{
bytesReceived = socket.Receive(buffer);
message += Encoding.ASCII.GetString(buffer, 0, bytesReceived);
} while (bytesReceived > 0);
Console.WriteLine(message);
}
接收到的字节是 ASCII 字符(在组成的协议中定义),因此接收到的每个字节都表示一个字符(不能转换部分接收到的多字节 unicode 字符)。字节被转换为字符串并附加到message 变量中。代码循环,直到服务器关闭连接。
当事先知道消息大小时,再次,根据所使用的协议,您可以创建一个消息缓冲区并将数据复制到每个Receive():
// Received using another Receive() call
int messageSize = 1234;
int totalBytesReceived = 0;
byte[] messageBuffer = new byte[messageSize];
byte[] buffer = new byte[BufferSize];
int bytesReceived;
do
{
bytesReceived = socket.Receive(buffer);
// Copy the receive buffer into the message buffer, appending after
// previously received data (totalBytesReceived).
Buffer.BlockCopy(buffer, 0, messageBuffer, totalBytesReceived, bytesReceived);
totalBytesReceived += bytesReceived;
} while (bytesReceived > 0);
// This assumes the connection wasn't closed prematurely.
Console.WriteLine(Encoding.ASCII.GetString(messageBuffer));
这又可以放在一个可重复使用的方法中:
public byte[] ReceiveMessage(Socket socket, int messageSize)
{
byte[] messageBuffer = new byte[messageSize];
int bytesReceived = 0;
int totalBytesReceived = 0;
do
{
byte[] buffer = new byte[BufferSize];
// Receive at most the requested number of bytes, or the amount the
// buffer can hold, whichever is smaller.
int toReceive = Math.Min(messageSize - totalBytesReceived, BufferSize);
bytesReceived = socket.Receive(buffer, toReceive, SocketFlags.None);
// Copy the receive buffer into the message buffer, appending after
// previously received data (totalBytesReceived).
Buffer.BlockCopy(buffer, 0, messageBuffer, totalBytesReceived, bytesReceived);
totalBytesReceived += bytesReceived;
} while (bytesReceived > 0);
if (totalBytesReceived < messageSize)
{
throw new Exception("Server closed connection prematurely");
}
return messageBuffer;
}
NetworkStream 包装了一个套接字,但它 has the same reading issues 作为套接字本身。您必须监控返回值并继续调用Read(),直到您收到所有字节。 TcpClient that has a GetStream() method 也是如此,您还将在其返回值上 have to continue reading until you've read all data。