使用阻止,流媒体.NET socket我正在连接到服务器。每当我读取少量数据时,一切都顺利,数据被接收到我的缓冲区中:
using (var socket = new Socket(SocketType.Stream, ProtocolType.IP))
{
socket.Connect(IPAddress.Parse("127.0.0.1"), 5000);
byte[] buffer = new byte[BufferSize];
socket.Receive(buffer);
// Here buffer doesn't always contain all data the server sent me?
Console.WriteLine(Encoding.Default.GetString(buffer));
}
但在某些情况下,我没有收到服务器发给我的所有内容。数据似乎被砍掉了。造成这种情况的原因是什么?
答案 0 :(得分:3)
这是documented in the Receive()
method,强调我的:
Receive方法将数据读入buffer参数,返回成功读取的字节数。您可以从面向连接的套接字和无连接套接字调用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。