beginSend和beginReceive

经过一番研究,终于可以确认,.net socket的beginSend和beginReceive用的是完成端口。(windows 98上不是,因为98没有这样的机制)。如果微软没有撒谎的话。
发送大量数据时,Socket.BeginSend和Socket.Send的速度是有差别的。在局域网里面,这种差别表现不明显。
但是在一个高延迟的网络中,差别就很大。
Socket.Send方法是可靠的。但是Send的时候,是等到缓冲区发出的包被确认以后才继续发送后续的包。所以,即使网络的带宽很大,但是如果网络延迟高,发送速度也会很慢。
Socket.BeginSend(异步)是把要发送的数据直接写入缓冲区,然后调用返回。BeginSend发送的时候,并不能确定发送是否成功。BeginSend的时候,指定了一个回调方法,发送成功后,系统会调用这个回调方法。在回调方法中,可以通过EndSend来检查实际发送的字节数。
虽然msdn中没有说明,但是实际上在EndSend中返回的字节数总是等于发送的字节数,或者抛出异常。
BeginSend的发送速度,可以占用全部的网络带宽。而Send的速度受网络延时的影响很大。在网络延迟高的网络中,可能每秒只有几K的速度。实际上,这个速度大致等于系统发送时的每个ip包的大小除以网络延迟的秒数。
完成端口使用的要点,就是减少系统中线程的数量。
所以,不要以为用了BeginSend就一定可以提高系统的负载能力。主要还是在于减少系统中工作的线程数量。所以,尽量不要在线程中使用阻塞的方法。

Socket.BeginReceive方法和Socket.Receive方法,对接受的速度没有影响。因为根据tcp协议,既然这个包已经到了应用 层,那么肯定是已经实际收到了。用BeginReceive的优势是在于可以不阻塞线程,从而减少系统中工作的线程。对于负载量不大的系统,用 Receive就可以了。Receive的逻辑比较简单。但是需要记住一点,Receive时返回的字节数,不一定等于要求读取的字节数。系统只是在数据 包到达时,尽可能的读取要求的字节数。

.net的Socket Api其实是对系统Socket Api的封装。所以以上的说法同样适用于winsock。但是由于BeginSend方法封装了完成端口,所以可以在获得高性能的同时,少了很多麻烦。对于网络的编程,是非常美妙的一件事情。

BeginSend需要注意的是,一定要控制发送的速度。否则,这个连接一定会因为系统缓冲区满而抛出异常。控制速度的办法就是在发送时计算发送的包数 量,在EndSend的时候计算发送成功的包数量。在发送之前,检查未发送的包数量,如果小于预设值则发送,否则暂停。这个地方会阻塞线程,所以也不是最 好的方法,比较好的办法,是自己做个发送缓冲队列。然后用一个专门的线程来处理发送。这样,只要用很少的线程,就可以处理发送。虽然BeginSend用 了完成端口,但是如果在系统中有大量被阻塞的线程,那就违背了完成端口的本意。

你可能感兴趣的