关于stream读取的问题,代码如下:class Class1
    {
        private static readonly object _syncRoot = new object();        private void PorcessClient(Object client)
        {
            TcpClient newClient = (TcpClient)client;
            try
            {
                lock (_syncRoot)
                {
                    byte[] bytes = new byte[1024];
                    StringBuilder clientData = new StringBuilder();
                    using (Stream ns = newClient.GetStream())
                    {
                        byte[] byteTemp = new byte[10048576];
                        Thread.Sleep(600);
                        int bytesRead = 0;
                        int tmp = 0;
                        do
                        {
                            try
                            {
                                bytesRead = ns.Read(bytes, 0, bytes.Length);
                                if (bytesRead > 0)
                                {
                                    for (int i = 0; i < bytes.Length; i++)
                                    {
                                        byteTemp[tmp + i] = bytes[i];
                                    }
                                    tmp += bytes.Length;
                                }
                            }
                            catch (IOException ioe)
                            {
                                bytesRead = 0;
                            }
                        } while (bytesRead == bytes.Length && bytesRead > 0);                        if ((tmp - bytes.Length + bytesRead) > 0)
                        {
                            clientData.Append(Encoding.Default.GetString(byteTemp, 0, tmp - bytes.Length + bytesRead));
                        }
                    }
                }
            }
            catch (Exception ecp)
            {
            }
            finally
            {
                if (newClient != null)
                    newClient.Close();
            }
        }
    }偷懒了一下,没写注释,不过相信大家都能看懂。问题是调用这个方法时,StringBuilder clientData这个值总是不能读取完整个发送过来的Stream ns = newClient.GetStream()数据。请大侠们赐教。

解决方案 »

  1.   

    我感觉主要就是这句有问题:byte[] bytes = new byte[1024],在传过来的数据比较大的时候就读不完整。
      

  2.   


    我说你抄个这类(我根本不愿意评说)代码怎么还纠结呢?!原来根本没有进入状况。“传过来的数据比较大”,那么代码中的do循环、以及“new byte[10048576]”你是一点没有作用?没有作用就删掉吧,否则放在那里不能骗别的程序员,反而把自己给蒙了。
      

  3.   

    首先帮你找到问题, } while (bytesRead == bytes.Length && bytesRead > 0);
    这个条件错了,如果最后一次读取不是缓存区的长度,bytesRead == bytes.Length 这个条件就为假,而即使是bytesRead > 0也没有用
    应该是这样的 } while (bytesRead > 0);
    只要是有读到数据就可以了,或是这样改也可以 } while (bytesRead == bytes.Length || bytesRead > 0);然后,给你一个简单点的代码class Class1
    {
    private static readonly object _syncRoot = new object(); private void PorcessClient( Object client )
    {
    TcpClient newClient = ( TcpClient )client;
    try
    {
    lock ( _syncRoot )
    {
    byte[] bytes = new byte[1024];
    StringBuilder clientData = new StringBuilder();
    using ( Stream ns = newClient.GetStream() )
    {
    byte[] byteTemp = new byte[10048576];
    Thread.Sleep( 600 );
    int bytesRead = 0;
    int tmp = 0;
    do
    {
    try
    {
    bytesRead = ns.Read( bytes, 0, bytes.Length );
    if ( bytesRead > 0 )
    {
    Array.Copy( bytes, 0, byteTemp, tmp, bytesRead );
    tmp += bytesRead;
    }
    }
    catch ( IOException ioe )
    {
    bytesRead = 0;
    }
    } while ( bytesRead > 0 ); if ( tmp > 0 )
    {
    clientData.Append( Encoding.Default.GetString( byteTemp, 0, tmp ) );
    }
    }
    }
    }
    catch ( Exception ecp )
    {
    }
    finally
    {
    if ( newClient != null )
    newClient.Close();
    }
    }
    }
      

  4.   


                            do
                            {
                                try
                                {
                                    bytesRead = ns.Read(bytes, 0, bytes.Length);
                                    if (bytesRead > 0)
                                    {
                                        for (int i = 0; i < bytesRead; i++)
                                        {
                                            byteTemp[tmp + i] = bytes[i];
                                        }
                                        tmp += bytesRead;
                                    }
                                }
                                catch (IOException ioe)
                                {
                                    bytesRead = 0;
                                }
                            } while (bytesRead > 0);
      

  5.   

    还有,byte[] byteTemp = new byte[10048576];你这个定义10M,那万一,数据流的长度超过10M,就会溢出了
      

  6.   

    回复sp1234:
    这个程序是别人写的,现在由我来修改,所以你说“我说你抄个这类(我根本不愿意评说)”这个我可以理解。我看过你很多回复别人的帖子,给你一点建议:你的技术是有大师的风范,但你的言论就不好说了。不要总是用教训别人的口气来说话,要知道人外有人,天外有天。
    回复Linux7985、wudliang:
    首先感谢你们的回复。其实本来程序里还有一个读取超时判断的,关于while里面的判断条件我也改成过你们的写法试过,但是改后运行总是卡到bytesRead = ns.Read(bytes, 0, bytes.Length),直到超时时间到了抛出异常。
    回复9楼:
    这个数据不会超过10M的,小的可能不到1k,大的不超过5M。
      

  7.   


    你的贴子是说,读取不完整
    StringBuilder clientData这个值总是不能读取完整个发送过来的Stream ns = newClient.GetStream()数据因此你说超时的话,那就不是程序的问题了
      

  8.   

    把条件换成
     while (ns.CanRead &&  bytesRead > 0);
    行不?
      

  9.   

    byte[] bytes = new byte[1024],在传过来的数据比较大的时候就读不完整
      

  10.   

    应该是读流的逻辑上的问题吧。整理一下思路应该就可以了吧不过需要注意的是.Stream关闭以后是读不出东西的。
      

  11.   


    那要看你对完整是怎么定义了,ns.Read(bytes, 0, bytes.Length);
    这个方法,其实是对已经到了你本机的数据进行读取,
    如果你的数据,还有一些在发送的路上,
    而本机又读取完成了,那么这个时候,你的BytesRead就是返回0,你就不会再读一去,实际上,这个时候,你的数据还是没有取完的,所以你的代码是有问题的。
    写一段伪代码while(true)     // 他是一个不停接收的过程。所以是死循环
    {
         // 定义一个临时的缓冲区bytes(大小为最大数据包的大小)
         int readCount = 0;
         int DataLen = 0; // 已有数据长度
         do
         {
              readCount = ns.Read(bytes, DataLen, bytes.Length);
              DataLen += readCount;
         }while(readCount > 0)
         
         if(DataLen > 0)
         {
              if(判断缓冲区数据是否有完整的数据包)
               {// 有
                   提取前N个字节,组成数据包
                     然后删除缓冲区前N个字节,缓冲区N个字节之后的数据全部移到最前,
                     DataLen -=N; 数据长度-N
              }
              else
              {// 没有完整的数据包
                   什么都不做,等待下一次循环,读取
              }
         }
         Thread.Sleep(600);   // 休息一下,再去read看看有没有数据。
    }
      

  12.   

    感谢Linux7985不辞辛苦的回复。
    我把程序做了下修改,把byte[] bytes = new byte[1024]改为byte[] bytes = new byte[4],这样如果传过来的数据字节数不为4的倍数时就可以正常读取(比较大的也可以),但是一旦为4的整数倍时,也就是为一次性读取字节数byte[4]的整数倍时,读完数据最后一次循环就会一直卡在bytesRead = ns.Read(bytes, 0, bytes.Length);这里不往下走了,搞不清楚怎么回事。
      

  13.   

    我监视过ns.CanRead的值,卡在那不动的时候ns.CanRead也是true,不是因为ns.CanRead为false了才卡那的。
      

  14.   


    刚才才看清楚,原来楼主写的是客户端代码,呵呵,TCPClient的Stream他是阻塞的,
    也就是说,如果没有数据的话,他就是会卡在哪里,不往下走了,(服务器端的没有发送数据,或是客户端还没有收到)总之这应该是正常的,
    参考一下,MSDNGetStream 返回一个可用来发送和接收数据的 NetworkStream。NetworkStream 类从 Stream 类继承,后者提供了大量为网络通信提供便利的方法和属性。必须首先调用 Connect 方法,否则 GetStream 方法将引发 InvalidOperationException。获取 NetworkStream 后,请调用 Write 方法将数据发送到远程主机。应调用 Read 方法来接收从远程主机传来的数据。这两种方法都将阻塞,直到执行了指定的操作为止。通过检查 DataAvailable 属性可避免对读取操作的阻止。true 值表示数据已从远程主机到达,可以进行读取。这样便保证立即完成 Read。如果远程主机已关闭连接,Read 将立即返回零字节。