首页 新闻 会员 周边 捐助

.NET Core 中从 Socket NetworkStream 读取数据的问题

0
悬赏园豆:200 [已解决问题] 解决于 2019-05-15 22:16

之前使用下面的代码从 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.",是不是就是表示这次网络数据传输已经结束?

dudu的主页 dudu | 高人七级 | 园豆:29333
提问于:2019-05-07 19:53
< >
分享
最佳答案
1

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?

收获园豆:200
BUTTERAPPLE | 老鸟四级 |园豆:3190 | 2019-05-07 20:08

经过实际验证,用 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;
}
dudu | 园豆:29333 (高人七级) | 2019-05-15 22:15

后来 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;
    }
}
dudu | 园豆:29333 (高人七级) | 2019-05-17 08:38
其他回答(2)
0

返回0,只是表示当前没有数据可以读取。不代表当前连接已经嗝屁了。

如果连接已经断开了,socket肯定是回throw 异常出来的,这是tcp协议决定了的,在查查是哪里出问题了,比如是不是有proxy之类的。

czd890 | 园豆:14488 (专家六级) | 2019-05-07 23:38
0

读取都会卡死, int currentRead = await _inputStream.ReadAsync(buffer, offset, shouldRead)根本没有用,当数据读到最后时并不会返回0,只会卡死

dongfp | 园豆:6 (初学一级) | 2024-09-18 09:14
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册