资源描述:
《写给unix程序员的windows异步io原理》由会员上传分享,免费在线阅读,更多相关内容在工程资料-天天文库。
1、写给Unix程序员的Windows异步IO原理本为假设你己经了解Unix_h的非阻塞socket是如何工作的。Windows上的select系统调用的时间复杂度是0(n),而不像epoll那样是个常数,这就是的select不适合开发高并发服务器的原因。本文就说说在Windows上开发高并发程序需要考虑哪些东东。类似epoll或者kqueue,Windows有自己的一套10多路转接器,叫做10完成端口(IOcompletionports),10完成端I丨就是用来轮询重叠10是否完成的对象。对10完成端口的操作是常数级别的。授木质的区别是,在Unix
2、你请求内核等待一个文件描述符是否nJ读,或者可写。而在重叠10和10完成端口里,程序员等待异步函数调用是否完成。比如,不是等待一个socket可写,然丿口在上面调用send(2),在重叠IO中,程序员直接调用WSASend,然后等待发送完毕。Unix的非阻塞10并不漂亮,Unix的一大抽象就是把所有东西都当做文件对待(精确地说是文件描述符),所以write(2)read(2),和close(2)也可以用在TCPsocket±,就像用在普通文件那样一般。异步操作在不同类型的文件上看起来很类似,但一旦因为性能的原因你使用了O_NONBLOCK标志,那
3、即使是授基本的操作也会冇很大的不同。普通文件并不支持非阻塞操作(可恶的是没有man文档提到这一点)。比如,程序员不能轮询一个普通的文件描述符,然后期望系统能在文件可进行非阻塞读操作时通知他o普通文件总是可读的,所以read(2)调用总是会占用调用线程的一段时间的。POSIX规范定义了一套异步接口,但是不同的Unix实现有不明确的地方。在Linux上,aio_*例程是使用pthread实现,并在libe库里提供的。io_submit(2)没有对应的libc包装,己经有人抱怨它太慢,还可以阻塞调用者。Solaris有真正的内核异步IO,但是不清楚对s
4、ocketIO来说它的性能如何。现代的高性能Unixsocket程序都通过在非阻塞文件描述符使用10多路分发器来达到高性能,而不是POSIXAIOoWindowsIO完成端口支持socket和普通文件,这大大简化了对硕盘的操作。比如,ReadFileEx()可以操作socket,也可以操作文件。作为笫一个例子,我们来看看ReadFile是怎么工作的。typedefvoid*HANDLE;BOOLReadFile(HANDLEfile,void*buffer,DWORDnumberOfBytesToRead,DWORD*numberOfBytesR
5、ead,OVERLAPPED*overlapped);这个函数既可以同步执行,也可以界步执行。同步操作会返回0,调用WSAGetLastError()返回WSA_IO_PENDING.当ReadFile是界步执行时,用户传入的OVERLAPPED*参数会指向未完成的操作。typedefstruct{unsignedlong*Internal;unsignedlong*InternalHigh;union{struct{WORDOffset;WORDOffsetHigh;};void*Pointer;};HANDLEhEvent;}OVERLAPP
6、ED;为了轮询函数的完成情况,可以在overlapper->hEvent上调用GetQueuedCompletionStatus().一个简单的TCP连接例子为了说明GetQueuedCompletionStatus的用法,假设现在己经有了一个localhost:8000上的连接。char*buffer[200];WSABUFb={buffer,200};size_tbytes_recvd;intr,total_events;OVERLAPPEDoverlapped;HANDLEport;port=CreateIoCompletionPort(I
7、NVALID_HANDLE_VALUE,NULL,NULL,0);if(!port){gotoerror;}r=WSARecv(socket,b,1,bytes_recvd,NULL,overlapped,NULL);CreateIoCompletionPort(port,overlapped.hEvent,if(r==0){if(WSAGetLastError()==WSA_IO_PENDING){/*Asynchronous*/GetQueuedCompletionStatus()if(r==WAIT_TIMEOUT){printf(Time
8、out);}else{)}else{/*Error*/printf(Error%d,WSAGetLastError());})e