为什么我的客户套接字没有收到我的服务器套接字发送的内容
使用阻塞,stream.NET套接字我连接到服务器。 每当我读取less量的数据,一切顺利,数据被接收到我的缓冲区中:
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)); }
但在某些情况下,我并没有收到服务器发给我的所有信息。 数据似乎被砍掉了。 这可能是什么原因?
这在Receive()
方法中有logging ,重点是mine:
Receive方法将数据读入缓冲区参数并返回成功读取的字节数 。 您可以从面向连接和无连接的套接字调用接收。
当忽略返回值时,你将不知道你的缓冲区的哪一部分实际上包含了相关的数据。 根据使用的协议,您可能会提前或不知道内容的长度。 一些协议提供这个长度,其他协议完成时closures连接,另一个协议可以使用消息边界。
您必须将接收到的数据保存在另一个缓冲区中,并在没有更多数据可用或预期时返回或输出整个消息缓冲区。 这可以这样做:
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字符)。 字节被转换为一个string并附加到message
variables。 代码循环直到服务器closures连接。
当事先知道消息大小时,根据使用的协议,您可以创build一个消息缓冲区,并在每个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
封装了一个套接字,但它与套接字本身具有相同的读取问题 。 您将不得不监视返回值,并保持调用Read()
直到您收到所有字节。 具有GetStream()
方法的TcpClient
也一样 ,在你读完所有数据之前,你还必须继续读取其返回值。