之前使用下面的代码从 NetworkStream 中读取数据,后来发现当服务器重启(tcp 连接断开)后,继续使用服务器重启前建立的 socket 连接(使用了 socket 连接池)从 NetworkStream 读取数据,并没有抛异常,而是 await ReadAsync 的返回值一直是 0 , 也就是下面的 currentRead 值一直为 0 ,结果造成死循环。
public async Task ReadAsync(byte[] buffer, int offset, int count)
{
int read = 0;
int shouldRead = count;
while (read < count)
{
int currentRead = await _inputStream.ReadAsync(buffer, offset, shouldRead);
if (currentRead < 1)
continue;
read += currentRead;
offset += currentRead;
shouldRead -= currentRead;
}
}
为了解决这个问题,今天将上面代码中的 continue
改为了 break
,但这样改是否会带来漏读数据的问题?有没有可能出现这样的情况:currentRead 为 0 时,下一个循环中还能读到数据?
NetworkStream.ReadAsync 方法帮助文档是这么写的:
// Returns:
// A task that represents the asynchronous read operation. The value of the TResult
// parameter contains the total number of bytes read into the buffer. The result
// value can be less than the number of bytes requested if the number of bytes currently
// available is less than the requested number, or it can be 0 (zero) if the end
// of the stream has been reached.
"the end of the stream has been reached.",是不是就是表示这次网络数据传输已经结束?
currentRead 为 0 说明 当前 Stream 已经没有其他数据了。
Read returns 0 only when there is no more data in the stream and no more is expected (such as a closed socket or end of file)
When does Network Stream Read returns 0?
经过实际验证,用 NetworkStream.ReadAsync 的返回值为0
判断 socket 数据读取完毕没问题,而用 NetworkStream.DataAvailable
进行判断,EnyimMemcachedCore 会出现大量
"Socket bound 'xxx' to has yyy unread data! This is probably a bug in the code" 错误。
最终采用的代码:
while (read < count)
{
int currentRead = await _inputStream.ReadAsync(buffer, offset, shouldRead);
if (currentRead == count || currentRead < 1)
break;
read += currentRead;
offset += currentRead;
shouldRead -= currentRead;
}
后来 github 上别人提交的 PR 中的改进代码
public async Task ReadAsync(byte[] buffer, int offset, int count)
{
int read = 0;
int shouldRead = count;
while (read < count)
{
int currentRead = await _inputStream.ReadAsync(buffer, offset, shouldRead);
if (currentRead == count)
break;
if (currentRead < 1)
throw new IOException("The socket seems to be disconnected");
read += currentRead;
offset += currentRead;
shouldRead -= currentRead;
}
}
返回0,只是表示当前没有数据可以读取。不代表当前连接已经嗝屁了。
如果连接已经断开了,socket肯定是回throw 异常出来的,这是tcp协议决定了的,在查查是哪里出问题了,比如是不是有proxy之类的。
读取都会卡死, int currentRead = await _inputStream.ReadAsync(buffer, offset, shouldRead)根本没有用,当数据读到最后时并不会返回0,只会卡死