基于StreamSocket的流返回的数据少于请求的

时间:2016-10-06 09:36:31

标签: c# sockets tcp uwp

这是关于如何处理返回少于请求的流的问题。我将展示如何处理它,然后非常欢迎评论。

但首先要做的事情是:

我使用基于UWP的{​​{1}}进行TCP通信。

StreamSocket

让我们说我们期待一个传输阻塞。前几个字节告诉我其中的事情,传输将持续多长时间。然后将流传递给一个方法,该方法将使用指定的缓冲区大小读取指定数量的数据。

第一次实施

StreamSocket strs = GetConnection();
Stream str = strs.InputStream.AsStreamForRead();

对于小型变速箱,我根本没有任何警告。然而,对于较大的传输,一旦传输大约为40kB,我就会比所请求的数据少得多。因此,通过此实现,我会丢失数据。

解决方案

所以我必须考虑到网络流上的阻塞读取可能会在某些时候返回少于请求的内容。所以我实现了这个解决方案:

// commencing data read:
int ret = 0;
int total = 0;
for(int k = 0; k < size; k += buffserSize) {
     int len = Math.Min(bufferSize, size - k);
     ret =  stream.Read(data, k, len);
     if(ret != len)
            Debug.WriteLine("Congestion: {0}/{1}", ret, len); // throw?
     total += ret;
 }

在大约40kB后我再次出现拥堵,但这次我考虑了它(并且作为奖励减少缓冲区大小=穷人 - 流量控制)

这让我想到了实际的

问题

为什么我需要期望基于 TCP Socket 的流返回的数据少于阻止读取所请求的数据。

我的印象是TCP已经拥有了它自己的流量控制。这就解释了为什么流量(字节/秒)增加然后(突然)降级。

但它确实解释为什么读取不等待,直到有足够的数据到达。我认为这应该在下面的一个抽象层处理。

2 个答案:

答案 0 :(得分:2)

  

我认为这应该在下面的一个抽象层处理。

为什么呢? TCP提供的抽象是两个方向上的(可能是无限的)字节流。如果你想要消息,你可以自己实现(就像你在这里一样)或者转移到更高层次的抽象

  

我的意思是Stream提供的抽象。但我似乎有一个误解。正如我所期望的那样,如果我请求n个字节

,则流给我n个字节

不幸的是,这也是一种误解。虽然一些Stream实现可能能够提供这样的保证,但抽象的Stream类定义了Read方法:

  

读入缓冲区的总字节数。如果当前没有多个字节可用,这可能小于请求的字节数

所以NetworkStream利用了这种灵活性 - 一旦有了一些数据,它就能给你至少一个字节,并且可以方便地提供它。

虽然它不适合您的使用案例,但可能是某些消费者能够使用任何可用的数据 - 因此他们可能提供大量缓冲区(如果有大量数据可用)但可以执行只有一个字节的东西。那些消费者将调用与您完全相同的API,并且其行为符合他们的需求。

答案 1 :(得分:0)

值得注意的是,BinaryReader类提供了一个名为ReadBytes(int count)的方法,它提供了我对此有误解的抽象层。

即只要它没有到达流的末尾,它就会返回请求的字节数:

  

返回值   键入:System.Byte []

     

包含从基础流读取的数据的字节数组。这可能小于达到流末尾时请求的字节数。

所以有一个更简单的解决方案:

var bReader = new BinaryReader(stream);
byte[] data = bReader.ReadBytes(size);

还是应该检查IOException