C# TcpClient未返回读取的所有行

C# TcpClient未返回读取的所有行,c#,tcpclient,C#,Tcpclient,正在尝试使用TcpClient类从远程主机获取一些文本。想在流中循环。读取,直到获得所有数据。如果我使用bytesRead>0它就会挂起。如果我运行这段代码,我只从远程主机获得第一行输出,程序正常退出。但是,如果我在do循环的第一行中断,并在调试器中手动完成每个迭代,我最终会得到我所期望的所有行。我真的不明白为什么会这样。这是我使用的代码: TcpClient client = new TcpClient("myserver.net", 1234);

正在尝试使用
TcpClient
类从远程主机获取一些文本。想在
流中循环。读取
,直到获得所有数据。如果我使用
bytesRead>0
它就会挂起。如果我运行这段代码,我只从远程主机获得第一行输出,程序正常退出。但是,如果我在do循环的第一行中断,并在调试器中手动完成每个迭代,我最终会得到我所期望的所有行。我真的不明白为什么会这样。这是我使用的代码:

            TcpClient client = new TcpClient("myserver.net", 1234);
            NetworkStream stream = client.GetStream();

            Byte[] buffer = new Byte[256];

            StringBuilder sb = new StringBuilder();
            int bytesRead;
            do
            {
                bytesRead = stream.Read(buffer, 0, buffer.Length);
                sb.Append(System.Text.Encoding.ASCII.GetString(buffer, 0, bytesRead));
            } while (bytesRead == 256);
如果每次迭代我都有意识地等待额外的时间,它似乎会得到我想要的,但我不明白为什么会发生这种情况

            StringBuilder sb = new StringBuilder();
            int bytesRead;
            do
            {
                System.Threading.Thread.Sleep(500);
                bytesRead = stream.Read(buffer, 0, buffer.Length);
                sb.Append(System.Text.Encoding.ASCII.GetString(buffer, 0, bytesRead));
            } while (bytesRead == 256);

它在调试器中工作的原因是,您正在将代码的速度降低到足以让网络缓冲区填满的程度。当您调用
stream.Read
并传入长度为256(
buffer.length
)时,这只会告诉流读取其缓冲区中达到该长度的任何内容。如果缓冲区中只有100个字节,它将只读取100个字节,返回值将为100。这可能是正在发生的情况(缓冲区没有完整的256字节可用),因此您的
while
条件不再满足,它正在打破循环


考虑到这一点,“所有的数据”不是没有某种协议就可以保证的。流本身可以在任何时候(从您的角度)在其缓冲区中显示数据。您要么需要实现某种长度规范(本质上是为消息提供一个报头结构,其中一部分描述消息的可变长度部分的长度),要么实现某种保留字节或字节序列作为终止符。然后,您知道读取特定数量的字节(除非您想引发异常,否则在读取之前不会退出),或者知道在遇到终止符字节或字节序列之前读取。

只需使用
StreamReader
,如注释中所述

TcpClient client = new TcpClient();
client.Connect("myserver.net", 1234);

var stream = new StreamReader(client.GetStream(),Encoding.ASCII);
string line = null;
while ((line = stream.ReadLine()) != null)
{
    Console.WriteLine(line);
}

while(bytesRead==256)
可能是错误的,因为网络流可能不会一次向您发送所有数据,它可能至少应该是
while(bytesRead!=0)
,尽管这是假设Read()阻塞的情况。此外,sb.Append()可能正在缓冲数据,这就是您看不到它的原因。如果它Read()阻塞并且从不返回0,那么它将永远阻塞,除非服务器关闭连接。这将提供我所期望的所有行,但它似乎在最后一行阻塞。我们从未点击null并退出循环。@user17753当另一端关闭连接时,您会得到什么?我怀疑另一端从未关闭连接。是的,它必须保持打开状态。@user17753那么接收方应该如何知道何时退出循环,除非您像SMTP一样发送一个特殊字符串,如
。我正在寻找与窗口过程中的
WSAAsyncSelect
WM#u SOCKET
消息的Winsock2/Win32 API等效的C#/.NET。例如,在文本框中填充从服务器传入的任何内容。