调整缓冲区长度,用于从NetworkStream读取小数据

时间:2011-11-25 13:52:08

标签: c# system.reactive tcpclient asyncsocket networkstream

如何在从TcpClient / NetworkStrem读取小数据时微调bufferSize? 如果bufferSize大到1024,4096读取/ BeginRead块。 如果我将bufferSize设置为16,32它可以无阻塞地工作。

  • 将bufferSize设置为1是否保证不会有任何块?性能影响会非常糟糕吗?
  • 看起来像将ReadTimeout设置为1000,2000等值 对阻止没有影响。有没有其他方法来阻止 要短吗? (NoDelay = true不起作用)

    public static IObservable<byte[]> AsyncReadChunk(this Stream stream, int bufferSize)
    {
        var buffer = new byte[bufferSize];
    
        return Observable.FromAsyncPattern<byte[], int, int, int>(stream.BeginRead, stream.EndRead)(buffer, 0, bufferSize)
            .Select(cbRead =>
                        {
                            var dataChunk = new byte[cbRead];
    
                            Buffer.BlockCopy(buffer, 0, dataChunk, 0, cbRead);
    
                            return dataChunk;
                        });
    }
    
    public static IObservable<byte[]> AsyncRead(this NetworkStream stream, int bufferSize)
    {
        return Observable.Defer(() => stream.DataAvailable ? AsyncReadChunk(stream, bufferSize) : Observable.Return(new byte[0]))
            .Repeat()
            .TakeWhile((dataChunk, index) => dataChunk.Length > 0);
    }
    

1 个答案:

答案 0 :(得分:2)

  

看起来像设置   ReadTimeout到1000,2000等值对阻塞没有影响。

Msdn说,使用异步BeginRead方法时,ReadTimeout无效。

  

将bufferSize设置为1是否保证不会有任何块?

不,原因不是。当没有通过连接发送单个字节时,无论缓冲区大小如何,Read调用都将被阻塞。

  

性能影响会非常糟糕吗?

我猜你在这里谈论的是1字节缓冲区。 这取决于您收到的数据的数量和频率以及您在EndRead上执行的代码。处理具有高带宽的流时,影响可能很大。您必须在接收数据时尝试观察您的cpu。

我不确定你想要分别达到你对阻塞的关注。

当您使用1024字节的缓冲区启动Receive(或Networkstream.Read),并且在套接字上接收10字节时,Read调用将在短暂延迟后返回10字节但不会阻塞直到整个缓冲区已填满。

  

还有其他方法可以缩短阻塞吗?

short 是什么意思?正如我所说,即使使用大缓冲区,Read也不会在接收少量数据时无休止地阻塞。

  

(NoDelay = true不起作用)

completely different这个故事可能很有意思,可以将你的发送方设置为true(如果你也控制了它)。

当设置为false(默认值)时,它会将发送到较大数据块的小数据块组合起来,以减少一个tcp数据包(40字节标头)的开销。

修改

  

我的意思是如果没有数据,NetworkStream.BeginRead会立即返回。

使用stream.DataAvailable怎么样?如果没有数据,它应该返回false。

此外,在使用异步模式时,如果有事情要做,那么调用是否会阻止预期的行为?否则,您将在繁忙的循环中进行活动轮询。

  

当缓冲区很大时,它有时等待60秒返回(当它没有完全填满或填充到一定量时)

嗯,不敢相信。您通过频道发送了哪些数据?每分钟1个字节?每秒1000字节?