关于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()数据。请大侠们赐教。
{
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()数据。请大侠们赐教。
我说你抄个这类(我根本不愿意评说)代码怎么还纠结呢?!原来根本没有进入状况。“传过来的数据比较大”,那么代码中的do循环、以及“new byte[10048576]”你是一点没有作用?没有作用就删掉吧,否则放在那里不能骗别的程序员,反而把自己给蒙了。
这个条件错了,如果最后一次读取不是缓存区的长度,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();
}
}
}
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);
这个程序是别人写的,现在由我来修改,所以你说“我说你抄个这类(我根本不愿意评说)”这个我可以理解。我看过你很多回复别人的帖子,给你一点建议:你的技术是有大师的风范,但你的言论就不好说了。不要总是用教训别人的口气来说话,要知道人外有人,天外有天。
回复Linux7985、wudliang:
首先感谢你们的回复。其实本来程序里还有一个读取超时判断的,关于while里面的判断条件我也改成过你们的写法试过,但是改后运行总是卡到bytesRead = ns.Read(bytes, 0, bytes.Length),直到超时时间到了抛出异常。
回复9楼:
这个数据不会超过10M的,小的可能不到1k,大的不超过5M。
你的贴子是说,读取不完整
StringBuilder clientData这个值总是不能读取完整个发送过来的Stream ns = newClient.GetStream()数据因此你说超时的话,那就不是程序的问题了
while (ns.CanRead && bytesRead > 0);
行不?
那要看你对完整是怎么定义了,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看看有没有数据。
}
我把程序做了下修改,把byte[] bytes = new byte[1024]改为byte[] bytes = new byte[4],这样如果传过来的数据字节数不为4的倍数时就可以正常读取(比较大的也可以),但是一旦为4的整数倍时,也就是为一次性读取字节数byte[4]的整数倍时,读完数据最后一次循环就会一直卡在bytesRead = ns.Read(bytes, 0, bytes.Length);这里不往下走了,搞不清楚怎么回事。
刚才才看清楚,原来楼主写的是客户端代码,呵呵,TCPClient的Stream他是阻塞的,
也就是说,如果没有数据的话,他就是会卡在哪里,不往下走了,(服务器端的没有发送数据,或是客户端还没有收到)总之这应该是正常的,
参考一下,MSDNGetStream 返回一个可用来发送和接收数据的 NetworkStream。NetworkStream 类从 Stream 类继承,后者提供了大量为网络通信提供便利的方法和属性。必须首先调用 Connect 方法,否则 GetStream 方法将引发 InvalidOperationException。获取 NetworkStream 后,请调用 Write 方法将数据发送到远程主机。应调用 Read 方法来接收从远程主机传来的数据。这两种方法都将阻塞,直到执行了指定的操作为止。通过检查 DataAvailable 属性可避免对读取操作的阻止。true 值表示数据已从远程主机到达,可以进行读取。这样便保证立即完成 Read。如果远程主机已关闭连接,Read 将立即返回零字节。