循环直到TcpClient响应完全读取

jim*_*jim 11 .net c# stream tcpclient

我写了一个简单的TCP客户端和服务器.问题在于客户.

我在阅读服务器的整个响应时遇到了一些麻烦.我必须让线程休眠以允许发送所有数据.

我已经尝试了几次将此代码转换为一个循环,直到服务器完成发送数据.

// Init & connect to client
TcpClient client = new TcpClient();
Console.WriteLine("Connecting.....");
client.Connect("192.168.1.160", 9988);

// Stream string to server
input += "\n";
Stream stm = client.GetStream();
ASCIIEncoding asen = new ASCIIEncoding();
byte[] ba = asen.GetBytes(input);
stm.Write(ba, 0, ba.Length);

// Read response from server.
byte[] buffer = new byte[1024];

System.Threading.Thread.Sleep(1000); // Huh, why do I need to wait?

int bytesRead = stm.Read(buffer, 0, buffer.Length);
response = Encoding.ASCII.GetString(buffer, 0, bytesRead);
Console.WriteLine("Response String: "+response);

client.Close();
Run Code Online (Sandbox Code Playgroud)

cas*_*One 28

构建在套接字之上的流的本质是,您有一个开放的管道,可以在套接字关闭之前传输和接收数据.

但是,由于客户端/服务器交互的性质,并不总是保证此管道上有要读取的内容.客户端和服务器必须同意通过管道发送内容.

当您Stream在.NET中使用抽象并将其覆盖在套接字的概念上时,客户端和服务器之间的协议要求仍然适用; 你可以打电话给Stream.Read所有你想要的,但是如果你Stream在另一边连接的插座没有发送内容,那么电话会等到有内容.

这就是协议存在的原因.在最基本的层面上,它们有助于定义双方之间发送的完整消息.通常,该机制的含义如下:

  • 带有长度前缀的消息,其中要在消息之前发送要读取的字节数
  • 用于标记消息结尾的字符模式(这种情况不太常见,具体取决于发送的内容,消息的任意部分越随意,使用的可能性越小)

那说你不是坚持上面的; 你的调用Stream.Read只是说"读取1024字节",实际上可能没有1024字节需要读取.如果是这种情况,则调用Stream.Read将阻止,直到填充完为止.

调用Thread.Sleep可能起作用的原因是因为在一秒钟过去的时候,它上面Stream有1024个字节要读取它并且它不会阻塞.

此外,如果您真的想要读取1024个字节,则不能假设调用Stream.Read将填充1024个字节的数据.该Stream.Read方法的返回值告诉您实际读取了多少字节.如果您的消息需要更多,那么您需要拨打其他电话Stream.Read.

如果你想要一个样本,Jon Skeet写下了完成这个的确切方法.

  • Jon Skeet的文章太棒了,谢谢你让我知道.+1 (3认同)