Microsoft建议套接字

时间:2014-03-05 18:02:37

标签: c# sockets

// message buffer
Byte[] dataByte = new Byte[RES_SIZE]; 
int readedBytes = 0; 

do // wait....
{ 
    Thread.Sleep(Delay); 
    message = string.Format("Waiting for messages, check number #{0}", readedBytes); 

} while (!networkStream.DataAvailable); 
//
// check for message
if (networkStream.DataAvailable)
{ 
    readedBytes = networkStream.Read(dataByte, 0, RES_SIZE); 
    //...
    //...
    //...
} 

我有一份关于以前代码的Microsoft建议书文档,即:

<小时/> 此代码显式依赖于NetworkStream.DataAvailable属性。虽然这不是不正确的,但确实如此 效率不高,因为它强制代码在嵌套的Thread.Sleep()调用的循环中测试这个属性, 这可以增加线程Context Switch /秒的数量,并可能导致一些 增加CPU使用率。

此外,这并不意味着没有使用Socket.ReceiveTimeout值,因为套接字是以阻塞模式配置的,因此无论如何NetworkStream.Read()调用都可能阻塞。

上面代码的第二个问题是它假定单个Read()操作将读取整个主机响应。虽然这对于小读取来说可能是正确的,但是这不是由Socket API保证,并且可能导致部分读取。

如果数据连接器不具备主机通信协议的内部知识,这将非常难以处理,因为它需要能够解释从套接字读取的数据以检测响应消息是否被完全读取。

此外,如果发生部分读取,一旦引入连接池,这可能会导致严重问题。请考虑以下情形:

  • 网站上的交易从池中获取新连接并向主机发送请求。
  • 主机回复1526字节的响应。
  • Connection对象尝试从套接字读取,但只读取1345个字节。
  • 由于连接认为它已从套接字读取了整个响应,因此它返回与池的连接并继续。

现在,想象一下当网站上的第二笔交易出现时会发生什么,请求a 来自池的连接并获得第一种情况下使用的相同连接:

  • 代码从池中获取连接并向主机发送新的请求消息
  • 主持人回复新的1520回复
  • 连接尝试从套接字读取并返回1701个字节。

也就是说,它获得了在第一次调用期间最初未读取的剩余181个字节,以及 完成第二次操作的响应。这可能会在调用者尝试时导致错误 解析主机响应并发现它是格式错误的。

建议的 强烈建议避免依赖Socket读取读取主机发送的整个消息, 虽然这种情况大部分时间都会在正常情况下发生,但这很容易在负载下或在负载下发生 网络拥塞。


有了这个介绍,我一直在寻找如何解决这个问题,但是,所有的例子都使用我使用的相同解决方案。

do // wait....
{
    //
    //
    //
} while (!networkStream.DataAvailable); 

问题: 我该如何解决这个问题?

1 个答案:

答案 0 :(得分:0)

读取socket中的SELECT方法。它需要一个套接字列表并返回那些有数据的套接字。

http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.select(v=vs.110).aspx

这允许你有一个循环检查x套接字,然后在单独的线程/任务中处理带有数据的循环。

http://books.google.pl/books?id=2zT5b2BS1OUC&pg=PA96&lpg=PA96&dq=socket.select+example+c%23&source=bl&ots=_JZzZY1zzQ&sig=AnGpQbL_GP2MR3Yk4oHNzJAqwU4&hl=en&sa=X&ei=fGgXU-frDorLsgas_YDwCw&ved=0CDwQ6AEwAw#v=onepage&q=socket.select%20example%20c%23&f=false

实际上有一些很好的讨论。它摘自“C#中的TCP / IP套接字:程序员实用指南”一书。