C# 如何从NetworkStream获取所有数据

C# 如何从NetworkStream获取所有数据,c#,tcp,tcpclient,tcp-ip,networkstream,C#,Tcp,Tcpclient,Tcp Ip,Networkstream,我试图读取通过TCP/IP连接的机器缓冲区中的所有数据,但我不知道为什么我没有获取所有数据,有些数据丢失了。 这是我正在使用的代码 using (NetworkStream stream = client.GetStream()) { byte[] data = new byte[1024]; int numBytesRead = stream.Read(data, 0, data.Length); if (numBytesRead > 0) {

我试图读取通过TCP/IP连接的机器缓冲区中的所有数据,但我不知道为什么我没有获取所有数据,有些数据丢失了。 这是我正在使用的代码

using (NetworkStream stream = client.GetStream())
{
    byte[] data = new byte[1024];
    int numBytesRead = stream.Read(data, 0, data.Length);
    if (numBytesRead > 0)
    {
       string str= Encoding.ASCII.GetString(data, 0, numBytesRead);
    }
}
请告诉我从机器上获取所有数据缺少什么。 提前感谢。

中的此示例演示了如何使用该属性执行此操作:

// Examples for CanRead, Read, and DataAvailable. 
// Check to see if this NetworkStream is readable. 
if(myNetworkStream.CanRead)
{
    byte[] myReadBuffer = new byte[1024];
    StringBuilder myCompleteMessage = new StringBuilder();
    int numberOfBytesRead = 0;

    // Incoming message may be larger than the buffer size. 
    do{
         numberOfBytesRead = myNetworkStream.Read(myReadBuffer, 0, myReadBuffer.Length);

         myCompleteMessage.AppendFormat("{0}", Encoding.ASCII.GetString(myReadBuffer, 0, numberOfBytesRead));

    }
    while(myNetworkStream.DataAvailable);

    // Print out the received message to the console.
    Console.WriteLine("You received the following message : " +
                                 myCompleteMessage);
}
else
{
     Console.WriteLine("Sorry.  You cannot read from this NetworkStream.");
}

TCP本身没有任何方法来定义“数据结束”条件。这是应用程序级portocol的职责

例如,请参见请求描述:

客户端请求(在本例中为请求行,仅包含一个标题字段)后接一个空行,因此请求以双换行结束

所以,对于请求端,数据由两个换行序列确定。回应:

Content Type指定HTTP消息传输的数据的Internet媒体类型,Content Length以字节为单位指示其长度

响应内容大小在数据之前的标题中指定。
因此,如何对一次传输的数据量进行编码取决于您自己——它可以是数据开头的2或4个字节,保存要读取的总大小,也可以是更复杂的方式(如果需要)。

代码的问题是,如果数据大小大于缓冲区大小(在您的情况下为1024字节),您将无法获得所有数据因此,您必须读取循环中的流。然后您可以
写入
内存流中的所有数据,直到
网络流结束


请尝试以下代码:

using (NetworkStream stream = client.GetStream())
    {
         while (!stream.DataAvailable)
         {
             Thread.Sleep(20);
         }
        
         if (stream.DataAvailable && stream.CanRead)
         {
              Byte[] data = new Byte[1024];
              List<byte> allData = new List<byte>();
        
              do
              {
                    int numBytesRead = stream.Read(data,0,data.Length);
    
                    if (numBytesRead == data.Length)
                    {
                         allData.AddRange(data);
                    }
                    else if (numBytesRead > 0)
                    {
                         allData.AddRange(data.Take(numBytesRead));
                    }                                    
               } while (stream.DataAvailable);
          }
    }
      
使用(NetworkStream=client.GetStream())
{
而(!stream.DataAvailable)
{
睡眠(20);
}
if(stream.DataAvailable&&stream.CanRead)
{
字节[]数据=新字节[1024];
List allData=新列表();
做
{
int numBytesRead=stream.Read(数据,0,数据.长度);
if(numBytesRead==data.Length)
{
allData.AddRange(数据);
}
否则如果(numBytesRead>0)
{
allData.AddRange(data.Take(numBytesRead));
}                                    
}while(stream.DataAvailable);
}
}

希望这能有所帮助,它可以防止您错过发送给您的任何数据。

在我的场景中,消息本身告诉您后续消息的长度。这是密码

 int lengthOfMessage=1024;
 string message = "";
 using (MemoryStream ms = new MemoryStream())
 {
      int numBytesRead;
      while ((numBytesRead = memStream.Read(MessageBytes, 0, lengthOfMessage)) > 0)
      {
            lengthOfMessage = lengthOfMessage - numBytesRead;
            ms.Write(MessageBytes, 0, numBytesRead);
      }
      message = Encoding.ASCII.GetString(ms.ToArray(), 0, (int)ms.Length);
 }
试试这个:

 private string GetResponse(NetworkStream stream)
    {
        byte[] data = new byte[1024];
        using (MemoryStream memoryStream = new MemoryStream())
        {
            do
            {
                stream.Read(data, 0, data.Length);
                memoryStream.Write(data, 0, data.Length);
            } while (stream.DataAvailable);

            return Encoding.ASCII.GetString(memoryStream.ToArray(), 0, (int)memoryStream.Length);
        }
    }

同步方法有时不显示请求主体。使用异步方法稳定地显示请求体

string request = default(string);
StringBuilder sb = new StringBuilder();

byte[] buffer = new  byte[client.ReceiveBufferSize];
int bytesCount;

if (client.GetStream().CanRead)
{
    do
    {
        bytesCount = client.GetStream().ReadAsync(buffer, 0, buffer.Length).Result;
        sb.Append(Encoding.UTF8.GetString(buffer, 0, bytesCount));
    }
    while(client.GetStream().DataAvailable);

    request = sb.ToString();
}

@George Sondrompilas的答案是正确的,但您可以使用CopyTo函数,而不是自己编写答案,该函数的作用与此相同:


这可能与您显式读取最多1024字节有关吗?@decPL好的,那么我如何读取所有数据?到底缺少什么?流的开始、结束还是随机字节?您能从字节序列中识别流的结尾吗?您知道数据的预期长度吗?@Aik它缺少随机字节。数据长度未知。它可以是任何内容?不,它不能是任何内容。如果不想等到客户机关闭连接,则需要定义协议。否则-继续阅读直到客户端关闭连接。这个例子做什么?
NetworkStream.DataAvailable
对于OP来说是否可靠?何时变为
false
?当套接字中没有更多数据时,我变为false,为什么不可靠?否。
NetworkStream.DataAvailable
false
仅表示接收器的接收缓冲区中没有数据。这并不意味着发送方已经完成了发送,因此它不能用于实现协议,也不能解决OP的问题。读一下你自己,你说我是对的,他要求读取流中的所有数据。我同意你的看法,他需要实现一个协议,但这不是问题,他问如何读取流中的所有数据。我高度怀疑OP想要的是什么,但你是对的。不,在str中,您将获得在读取时存储在
网络流中的整个字符串。您的意思是说缓冲区中的所有可用数据。对吗?在网络流中使用MemoryStream也是一个可能的解决方案:)+1如果您想要使用代码并扩展它的方法,请检查其他答案。尝试调试您使用的代码并了解每一步发生的情况,这可能会对您有所帮助。我在'while(numBytesRead=stream.Read(data,0,data.Length)>0'处遇到错误,无法将bool转换为int,并且当前上下文和代码的最后一行
Encoding.ASCII.GetString(ms.ToArray)中不存在
buffer
(),0,ms.Length);
小心。此解决方案在
使用
部分结束后关闭连接。我将用
var readCount=stream.Read(data,0,data.Length);
memoryStream.Write(data,0,readCount);
分别替换第8行和第9行。这样就不会得到后面的0字节,而转换成
“\0”
输出字符串中的空字符。
string request = default(string);
StringBuilder sb = new StringBuilder();

byte[] buffer = new  byte[client.ReceiveBufferSize];
int bytesCount;

if (client.GetStream().CanRead)
{
    do
    {
        bytesCount = client.GetStream().ReadAsync(buffer, 0, buffer.Length).Result;
        sb.Append(Encoding.UTF8.GetString(buffer, 0, bytesCount));
    }
    while(client.GetStream().DataAvailable);

    request = sb.ToString();
}