WinSock和异步io

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/linfengmove/article/details/81236626

        一般Socket本身可以设置属性,阻塞或者非阻塞,阻塞模式下accept,connect,send,recv,sendto,recvfrom操作都会等待socket的信号,send要等待操作完成后才会返回,等待的时间也是在等socket的状态变为可写。只不过等待的操作由操作系统来做,当前线程被挂起了。recv同理也一样。非阻塞则是不管可写或者非可写send都会直接返回,可写send返回写入的字节数,不可写返回socket_error.这时候要不采用循环send的方法,直到send成功,或者用select先去检查socket是否可写再进行send写入操作,同理recv也相同,检测是否可读,再recv读入数据。

        这中间其实有个问题,就是无论是用阻塞或者非阻塞,都只有当socket的状态为可写或者可读的时候,所有的操作才会成功,借助于select可以帮助我们提前检测socket的状态,舍去不必要的等待或者循环(也是等待,不过中间可以做点事情)。而且select可以加入多个socket,并且可以设置超时,这个时候如果所有socket都没有发生信号改变,可以做点额外的事情。

    但是在Windows下提供了一套更好的功能,就是将socket读写和重叠IO(异步io)结合起来,只要将原有的send,recv,sendto,recvfrom改为WSASend,WSARecv,WSASendto,WSARecvFrom就可以享受到这一优势。重叠io的好处是无论socket是阻塞还是非阻塞该投递操作都会立即返回。操作完成会通过Overlapped结构中的一个event进行通知。比如WSARecv这个操作投递后,如果收到了event通知io完成,我们直接可以用buf中的数据,操作系统已经把数据从内核copy到了我们的用户缓冲中。这就比select更进一步,select只能发现socket状态改变,然后我们还需要调用recv去从内核copy数据。

          当然更有优势的事情是,重叠io和结合iocp(完成端口)来接受更多的连接,因为上面的事件模型,需要用WaitForMultiEvent去发现事件的状态改变,但是WSAWaitForMultipleEvent等待的句柄有上限只有64个。所以如果连接数很多,则需要将重叠io和完成端口结合起来。

猜你喜欢

转载自blog.csdn.net/linfengmove/article/details/81236626