以文本方式查看主题 - 计算机科学论坛 (http://bbs.xml.org.cn/index.asp) -- 『 C/C++编程思想 』 (http://bbs.xml.org.cn/list.asp?boardid=61) ---- 很幽默的讲解六种Socket I/O模型[转帖] (http://bbs.xml.org.cn/dispbbs.asp?boardid=61&rootid=&id=40669) |
-- 作者:longshentailang -- 发布时间:11/29/2006 10:46:00 PM -- 很幽默的讲解六种Socket I/O模型[转帖] 作者: 来源:zz 发表时间:2006-07-30 信息来源:幻影论坛 作 者: flyinwuhan (制怒·三思而后行) 一:select模型 老陈有一个在外地工作的女儿,不能经常回来,老陈和她通过信件联系。他们的信会被邮递员投递到他们的信箱里。 一:select模型 老陈非常想看到女儿的信。以至于他每隔10分钟就下楼检查信箱,看是否有女儿的信~~~~~ 使用线程来select应该是通用的做法: while (not Terminated) do shutdown( MainSock, SD_BOTH ); 后来,老陈使用了微软公司的新式信箱。这种信箱非常先进,一旦信箱里有新的信件,盖茨就会给老陈打电话:喂,大爷,你有新的信件了!从此,老陈再也不必频繁上下楼检查信箱了,牙也不疼了,你瞅准了,蓝天......不是,微软~~~~~~~~ WSAAsyncSelect模型是Windows下最简单易用的一种Socket I/O模型。使用这种模型时,Windows会把网络事件以消息的形势通知应用程序。 sock := socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); WSAAsyncSelect( m_sock, Handle, WM_SOCKET, FD_ACCEPT or FD_CLOSE ); listen( m_sock, 5 ); 应用程序可以对收到WM_SOCKET消息进行分析,判断是哪一个socket产生了网络事件以及事件类型: procedure TfmMain.WMSocket(var Msg: TMessage); FD_CLOSE : closesocket( Msg.WParam ); 三:WSAEventSelect模型 后来,微软的信箱非常畅销,购买微软信箱的人以百万计数......以至于盖茨每天24小时给客户打电话,累得腰酸背痛,喝蚁力神都不好使~~~~~~ 同样要使用线程: while ( not Terminated ) do if ( ne.lNetworkEvents and FD_ACCEPT ) > 0 then ret := sizeof(adr); hEvent := WSACreateEvent(); if ( ne.lNetworkEvents and FD_READ ) > 0 then |
-- 作者:longshentailang -- 发布时间:11/29/2006 10:47:00 PM -- 四:Overlapped I/O 事件通知模型 后来,微软通过调查发现,老陈不喜欢上下楼收发信件,因为上下楼其实很浪费时间。于是微软再次改进他们的信箱。新式的信箱采用了更为先进的技术,只要用户告诉微软自己的家在几楼几号,新式信箱会把信件直接传送到用户的家中,然后告诉用户,你的信件已经放到你的家中了!老陈很高兴,因为他不必再亲自收发信件了! Overlapped I/O 事件通知模型和WSAEventSelect模型在实现上非常相似,主要区别在"Overlapped",Overlapped模型是让应用程序使用重叠数据结构(WSAOVERLAPPED),一次投递一个或多个Winsock I/O请求。这些提交的请求完成后,应用程序会收到通知。什么意思呢?就是说,如果你想从socket上接收数据,只需要告诉系统,由系统为你接收数据,而你需要做的只是为系统提供一个缓冲区~~~~~ while ( not Terminated ) do WSAResetEvent( FLinks.Events[Index] ); if dwTemp = 0 then //连接已经关闭 //初始化缓冲区 //递一个接收数据请求 五:Overlapped I/O 完成例程模型 老陈接收到新的信件后,一般的程序是:打开信封----掏出信纸----阅读信件----回复信件......为了进一步减轻用户负担,微软又开发了一种新的技术:用户只要告诉微软对信件的操作步骤,微软信箱将按照这些步骤去处理信件,不再需要用户亲自拆信/阅读/回复了!老陈终于过上了小资生活! Overlapped I/O 完成例程要求用户提供一个回调函数,发生新的网络事件的时候系统将执行这个函数: 六:IOCP模型 微软信箱似乎很完美,老陈也很满意。但是在一些大公司情况却完全不同!这些大公司有数以万计的信箱,每秒钟都有数以百计的信件需要处理,以至于微软信箱经常因超负荷运转而崩溃!需要重新启动!微软不得不使出杀手锏...... "Windows NT小组注意到这些应用程序的性能没有预料的那么高。特别的,处理很多同时的客户请求意味着很多线程并发地运行在系统中。因为所有这些线程都是可运行的[没有被挂起和等待发生什么事],Microsoft意识到NT内核花费了太多的时间来转换运行线程的上下文[Context],线程就没有得到很多CPU时间来做它们的工作。大家可能也都感觉到并行模型的瓶颈在于它为每一个客户请求都创建了一个新线程。创建线程比起创建进程开销要小,但也远不是没有开销的。我们不妨设想一下:如果事先开好N个线程,让它们在那hold[堵塞],然后可以将所有用户的请求都投递到一个消息队列中去。然后那N个线程逐一从消息队列中去取出消息并加以处理。就可以避免针对每一个用户请求都开线程。不仅减少了线程的资源,也提高了线程的利用率。理论上很不错,你想我等泛泛之辈都能想出来的问题,Microsoft又怎会没有考虑到呢?"-----摘自nonocast的《理解I/O Completion Port》 先看一下IOCP模型的实现: //创建一个完成端口 //接受远程连接,并把这个连接的socket句柄绑定到刚才创建的IOCP上 //创建CPU数*2 + 2个线程 OK,就这么简单,我们要做的就是建立一个IOCP,把远程连接的socket句柄绑定到刚才创建的IOCP上,最后创建n个线程,并告诉这n个线程到这个IOCP上去访问数据就可以了。 再看一下TRecvSendThread线程都干些什么: procedure TRecvSendThread.Execute; if BytesTransd <> 0 then //再投递一个读数据请求 读写线程只是简单地检查IOCP是否完成了我们投递的读写操作,如果完成了则再投递一个新的读写请求。 |
-- 作者:longshentailang -- 发布时间:11/29/2006 10:50:00 PM -- 不好意思,由于前些天在C/C++版块发不了帖,导致发了很多无用的帖子。现在补发一下! |
-- 作者:卷积内核 -- 发布时间:11/30/2006 11:25:00 AM -- 很不错,支持一下。继续努力 |
W 3 C h i n a ( since 2003 ) 旗 下 站 点 苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》 |
296.875ms |