




已阅读5页,还剩18页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
最先出现的是阻塞模型,这个模型是讲解计算机网络时被作为例子介绍的,也是最简单的。其基本原理是:首先建立一个socket连接,然后对其进行操作,比如,从该socket读数据。因为网络传输是要一定的时间的,即使网络通畅的情况下,接受数据的操作也要花费时间。对于一个简单的单线程程序,接收数据的过程是无法处理其他操作的。比如一个窗口程序,当你接收数据时,点击按钮或关闭窗口操作都不会有效。它的缺点显而易见,一个线程你只能处理一个socket,用来教课还行,实际使用效果就不行了。为了处理多个socket连接,聪明的人们发明了select模型。该模型以集合来管理socket连接,每次去查询集合中的socket状态,从而达到处理多连接的能力,其函数原型是int select(int nfds, fd_set FAR * readfds, fd_set FAR * writefds, fd_set FAR * exceptfds, const struct timeval FAR * timeout)。比如我们判断某个socket是否有数据可读,我们首先将一个fdread集合置空,然后将socket加入到该集合,调用select(0,&fdread,NULL,NULL,NULL),之后我们判断socket是否还在fdread中,如果还在,则说明有数据可读。数据的读取和阻塞模型相同,调用recv函数。但是每个集合容量都有一个限值,默认情况下是64个,当然你可以重新定义它的大小,但还是有一个最上限,自己设置也不能超过该值,一般情况下是1024。尽管select模型可以处理多连接,但集合的管理多少让人感到繁琐。熟悉windows操作系统的都知道,其窗口处理是基于消息的。人们又发明了一种新的网络模型WSAAsyncSelect模型,即异步选择模型。该模型为每个socket绑定一个消息,当socket上出现事先设置的socket事件时,操作系统就会给应用程序发送这个消息,从而对该socket事件进行处理,其函数原型是int WSAAsynSelect(SOCKET s, HWND hWnd, unsigned int wMsg, long lEvent)。hWnd指明接收消息的句柄,wMsg指定消息ID,lEvent按位设置感兴趣的网络事件,入WSAAsyncSelect(s,hwnd,WM_SOCKET, FD_CONNECT | FD_READ | FD_CLOSE)。该模型的优点是在系统开销不大的情况下同时处理许多连接,也不需要什么集合管理。缺点很明显,即使你的程序不需要窗口,也要专门为WSAAsyncSelect模型定义一个窗口。另外,让单个窗口去处理成千上万的socket操作事件,很可能成为性能瓶颈。与WSAAsynSelect模型类似,人们还发明了WSAEventSelect模型,即事件选择模型。看名字就可以猜测出来,它是基于事件的。WSAAsynSelect模型在出现感兴趣的socket事件时,系统会发一个相应的消息。而WSAEventSelect模型在出现感兴趣的socket事件时,系统会将相应WSAEVENT事件设为传信。可能你现在对sokect事件和普通WSAEVENT事件还不是很清楚。socket事件是与socket操作相关的一些事件,如FD_READ,FD_WRITE,FD_ACCEPT等。而WSAEVENT事件是传统的事件,该事件有两种状态,传信(signaled)和未传信(non-signaled)。所谓传信,就是事件发生了,未传信就是还没有发生。我们每次建立一个连接,都为其绑定一个事件,等到该连接变化时,事件就会变为传信状态。那么,谁去接受这个事件变化呢?我们通过一个WSAWaitForMultipleEvents(.)函数来等待事件发生,传入参数中的事件数组中,只有有一个事件发生,该函数就会返回(也可以设置为所有事件发生才返回,在这里没用),返回值为事件的数组序号,这样我们就知道了哪个事件发生了,也就是该事件对应的socket有了socket操作事件。该模型比起WSAAsynSelect模型的优势很明显,不需要窗口。唯一缺点是,该模型每次只能等待64个事件,这一限制使得在处理多socket时,有必要组织一个线程池,伸缩性不如后面要讲的重叠模型。重叠I/O(Overlapped I/O)模型使应用程序达到更佳的系统性能。重叠模型的基本设计原理是让应用程序使用重叠数据结构,一次投递一个或多个Winsock I/O请求。重叠模型到底是什么东西呢?可以与WSAEventSelect模型做类比(其实不恰当,后面再说),事件选择模型为每个socket连接绑定了一个事件,而重叠模型为每个socket连接绑定了一个重叠。当连接上发生socket事件时,对应的重叠就会被更新。其实重叠的高明之处在于,它在更新重叠的同时,还把网络数据传到了实现指定的缓存区中。我们知道,前面的网络模型都要用户自己通过recv函数来接受数据,这样就降低了效率。我们打个比方,WSAEventSelect模型就像邮局的包裹通知,用户收到通知后要自己去邮局取包裹。而重叠模型就像送货上门,邮递员发给你通知时,也把包裹放到了你事先指定的仓库中。 重叠模型又分为事件通知和完成例程两种模式。在分析这两种模式之前,我们还是来看看重叠数据结构: typedef struct WSAOVERLAPPED DWORD Internal; DWORD InternalHigh; DWORD Offset; DWORD OffsetHigh; WSAEVENT hEvent; WSAOVERLAPPED, FAR * LPWSAOVERLAPPED; 该数据结构中,Internal、InternalHigh、Offset、OffsetHigh都是系统使用的,用户不用去管,唯一关注的就是hEvent。如果使用事件通知模式,那么hEvent就指向相应的事件句柄。如果是完成例程模式,hEvent设为NULL。我们现在来看事件通知模式,首先创建一个事件hEvent,并创建一个重叠结构AcceptOverlapped,并设置AcceptOverlapped.hEvent = hEvent,DataBuf是我们事先设置的数据缓存区。调用WSARecv(AcceptSocket,&DataBuf,1,&RecvBytes,&Flags,&AcceptOverlapped,NULL),则将AcceptSocket与AcceptOverlapped重叠绑定在了一起。当接收到数据以后,hEvent就会设为传信,而数据就会放到DataBuf中。我们再通过WSAWaitForMultipleEvents(.)接收到该事件通知。这里我们要注意,既然是基于事件通知的,那它就有一个事件处理上限,一般为64。 完成例程和事件通知模式的区别在于,当相应的socket事件出现时,系统会调用用户事先指定的回调函数,而不是设置事件。其实就是将WSARecv的最后一个参数设为函数指针。该回调函数的原型如下: void CALLBACK CompletionROUTINE( DWORD dwError, DWORD cbTransferred, LPWSAOVERLAPPED lpOverlapped, DWORD dwFlags ); 其中,cbTransferred表示传输的字节数,lpOverlapped是发生socket事件的重叠指针。我们调用WSARecv(AcceptSocket,&DataBuf,1,&RecvBytes,&Flags,&AcceptOverlapped,WorkerRoutine)将AcceptSocket与WorkRoutine例程绑定。这里有一点小提示,当我们创建多个socket的连接时,最好把重叠与相应的数据缓存区用一个大的数据结构放到一块,这样,我们在例程中通过lpOverlapped指针就可以直接找到相应的数据缓存区。这里要注意,不能将多个重叠使用同一个数据缓存区,这样在多个重叠都在处理时,就会出现数据混乱。下面我们来介绍专门用于处理为数众多socket连接的网络模型完成端口。因为需要做出大量的工作以便将socket添加到一个完成端口,而其他方法的初始化步骤则省事多了,所以对新手来说,完成端口模型好像过于复杂了。然而,一旦弄明白是怎么回事,就会发现步骤其实并非那么复杂。所谓完成端口,实际是Windows采用的一种I/O构造机制,除套接字句柄之外,还可以接受其他东西。使用这种模式之前,首先要创建一个I/O完成端口对象,该函数定义如下: HANDLE CreateIoCompletionPort( HANDLE FileHandle, HANDLE ExistingCompletionPort, DWORD CompletionKey, DWORD NumberOfConcurrentThreads ); 该函数用于两个截然不同的目的:1)用于创建一个完成端口对象。2)将一个句柄同完成端口关联到一起。 通过参数NumberOfConcurrentThreads,我们可以指定同时运行的线程数。理想状态下,我们希望每个处理器各自负责一个线程的运行,为完成端口提供服务,避免过于频繁的线程任务切换。对于一个socket连接,我们通过CreateIoCompletionPort(HANDLE)Accept,CompletionPort,(DWORD)PerHandleData,0)将Accept连接与CompletionPort完成端口绑定到一起,CompetionPort对应的那些线程不断通过GetQueuedCompletionStatus来查询与其关联的socket连接是否有I/O操作完成,如果有,则做相应的数据处理,然后通过WSARecv将该socket连接再次投递,继续工作。完成端口在性能和伸缩性方面表现都很好,相关联的socket连接数目没有限制。 上面介绍了6种socket编程模型,好像现在已经有新的模型出现两种I/O模式 阻塞模式:执行I/O操作完成前会一直进行等待,不会将控制权交给程序。套接字默认为阻塞模式。可以通过多线程技术进行处理。 非阻塞模式:执行I/O操作时,Winsock函数会返回并交出控制权。这种模式使用起来比较复杂,因为函数在没有运行完成就进行返回,会不断地返回WSAEWOULDBLOCK错误。但功能强大。WindowsSocket五种I/O模型如果你想在Windows平台上构建服务器应用,那么I/O模型是你必须考虑的。Windows操作系统提供了选择(Select)、异步选择(WSAAsyncSelect)、事件选择(WSAEventSelect)、重叠I/O(OverlappedI/O)和完成端口(CompletionPort)共五种I/O模型。每一种模型均适用于一种特定的应用场景。程序员应该对自己的应用需求非常明确,而且综合考虑到程序的扩展性和可移植性等因素,作出自己的选择。我们假设客户端的代码如下(为代码直观,省去所有错误检查,以下同):#include#include#defineSERVER_ADDRESS137.117.2.148#definePORT5150#defineMSGSIZE1024#pragmacomment(lib,ws2_32.lib)intmain()WSADATAwsaData;SOCKETsClient;SOCKADDR_INserver;charszMessageMSGSIZE;intret;/InitializeWindowssocketlibraryWSAStartup(0x0202,&wsaData);/CreateclientsocketsClient=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);/Connecttoservermemset(&server,0,sizeof(SOCKADDR_IN);server.sin_family=AF_INET;server.sin_addr.S_un.S_addr=inet_addr(SERVER_ADDRESS);server.sin_port=htons(PORT);connect(sClient,(structsockaddr*)&server,sizeof(SOCKADDR_IN);while(TRUE)printf(Send:);gets(szMessage);/Sendmessagesend(sClient,szMessage,strlen(szMessage),0);/Receivemessageret=recv(sClient,szMessage,MSGSIZE,0);szMessageret=0;printf(Received%dbytes:%sn,ret,szMessage);/Cleanupclosesocket(sClient);WSACleanup();return0;客户端所做的事情相当简单,创建套接字,连接服务器,然后不停的发送和接收数据。比较容易想到的一种服务器模型就是采用一个主线程,负责监听客户端的连接请求,当接收到某个客户端的连接请求后,创建一个专门用于和该客户端通信的套接字和一个辅助线程。以后该客户端和服务器的交互都在这个辅助线程内完成。这种方法比较直观,程序非常简单而且可移植性好,但是不能利用平台相关的特性。例如,如果连接数增多的时候(成千上万的连接),那么线程数成倍增长,操作系统忙于频繁的线程间切换,而且大部分线程在其生命周期内都是处于非活动状态的,这大大浪费了系统的资源。所以,如果你已经知道你的代码只会运行在Windows平台上,建议采用WinsockI/O模型。一.选择模型 Select(选择)模型是Winsock中最常见的I/O模型。之所以称其为“Select模型”,是由于它的“中心思想”便是利用select函数,实现对I/O的管理。最初设计该模型时,主要面向的是某些使用UNIX操作系统的计算机,它们采用的是Berkeley套接字方案。Select模型已集成到Winsock1.1中,它使那些想避免在套接字调用过程中被无辜“锁定”的应用程序,采取一种有序的方式,同时进行对多个套接字的管理。由于Winsock1.1向后兼容于Berkeley套接字实施方案,所以假如有一个Berkeley套接字应用使用了select函数,那么从理论角度讲,毋需对其进行任何修改,便可正常运行。(节选自Windows网络编程第八章)下面的这段程序就是利用选择模型实现的Echo服务器的代码(已经不能再精简了):#include#include#definePORT5150#defineMSGSIZE1024#pragmacomment(lib,ws2_32.lib)intg_iTotalConn=0;SOCKETg_CliSocketArrFD_SETSIZE;DWORDWINAPIWorkerThread(LPVOIDlpParameter);intmain()WSADATAwsaData;SOCKETsListen,sClient;SOCKADDR_INlocal,client;intiaddrSize=sizeof(SOCKADDR_IN);DWORDdwThreadId;/InitializeWindowssocketlibraryWSAStartup(0x0202,&wsaData);/CreatelisteningsocketsListen=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);/Bindlocal.sin_addr.S_un.S_addr=htonl(INADDR_ANY);local.sin_family=AF_INET;local.sin_port=htons(PORT);bind(sListen,(structsockaddr*)&local,sizeof(SOCKADDR_IN);/Listenlisten(sListen,3);/CreateworkerthreadCreateThread(NULL,0,WorkerThread,NULL,0,&dwThreadId);while(TRUE)/AcceptaconnectionsClient=accept(sListen,(structsockaddr*)&client,&iaddrSize);printf(Acceptedclient:%s:%dn,inet_ntoa(client.sin_addr),ntohs(client.sin_port);/Addsockettog_CliSocketArrg_CliSocketArrg_iTotalConn+=sClient;return0;DWORDWINAPIWorkerThread(LPVOIDlpParam)inti;fd_setfdread;intret;structtimevaltv=1,0;charszMessageMSGSIZE;while(TRUE)FD_ZERO(&fdread);for(i=0;ig_iTotalConn;i+)FD_SET(g_CliSocketArr,&fdread);/Weonlycarereadeventret=select(0,&fdread,NULL,NULL,&tv);if(ret=0)/Timeexpiredcontinue;for(i=0;ig_iTotalConn;i+)if(FD_ISSET(g_CliSocketArr,&fdread)/Areadeventhappenedong_CliSocketArrret=recv(g_CliSocketArr,szMessage,MSGSIZE,0);if(ret=0|(ret=SOCKET_ERROR&WSAGetLastError()=WSAECONNRESET)/Clientsocketclosedprintf(Clientsocket%dclosed.n,g_CliSocketArr);closesocket(g_CliSocketArr);if(ig_iTotalConn-1)g_CliSocketArri-=g_CliSocketArr-g_iTotalConn;else/WereceivedamessagefromclientszMessageret=0;send(g_CliSocketArr,szMessage,strlen(szMessage),0);return0;服务器的几个主要动作如下:1.创建监听套接字,绑定,监听;2.创建工作者线程;3.创建一个套接字数组,用来存放当前所有活动的客户端套接字,每accept一个连接就更新一次数组;4.接受客户端的连接。这里有一点需要注意的,就是我没有重新定义FD_SETSIZE宏,所以服务器最多支持的并发连接数为64。而且,这里决不能无条件的accept,服务器应该根据当前的连接数来决定是否接受来自某个客户端的连接。一种比较好的实现方案就是采用WSAAccept函数,而且让WSAAccept回调自己实现的ConditionFunction。如下所示:intCALLBACKConditionFunc(LPWSABUFlpCallerId,LPWSABUFlpCallerData,LPQOSlpSQOS,LPQOSlpGQOS,LPWSABUFlpCalleeId,LPWSABUFlpCalleeData,GROUPFAR*g,DWORDdwCallbackData)if(当前连接数FD_SETSIZE)returnCF_ACCEPT;elsereturnCF_REJECT;工作者线程里面是一个死循环,一次循环完成的动作是:1.将当前所有的客户端套接字加入到读集fdread中;2.调用select函数;3.查看某个套接字是否仍然处于读集中,如果是,则接收数据。如果接收的数据长度为0,或者发生WSAECONNRESET错误,则表示客户端套接字主动关闭,这时需要将服务器中对应的套接字所绑定的资源释放掉,然后调整我们的套接字数组(将数组中最后一个套接字挪到当前的位置上)除了需要有条件接受客户端的连接外,还需要在连接数为0的情形下做特殊处理,因为如果读集中没有任何套接字,select函数会立刻返回,这将导致工作者线程成为一个毫无停顿的死循环,CPU的占用率马上达到100%。关系到套接字列表的操作都需要使用循环,在轮询的时候,需要遍历一次,再新的一轮开始时,将列表加入队列又需要遍历一次.也就是说,Select在工作一次时,需要至少遍历2次列表,这是它效率较低的原因之一.在大规模的网络连接方面,还是推荐使用IOCP或EPOLL模型.但是Select模型可以使用在诸如对战类游戏上,比如类似星际这种,因为它小巧易于实现,而且对战类游戏的网络连接量并不大.对于Select模型想要突破Windows64个限制的话,可以采取分段轮询,一次轮询64个.例如套接字列表为128个,在第一次轮询时,将前64个放入队列中用Select进行状态查询,待本次操作全部结束后.将后64个再加入轮询队列中进行轮询处理.这样处理需要在非阻塞式下工作.以此类推,Select也能支持无限多个.二.异步选择Winsock提供了一个有用的异步I/O模型。利用这个模型,应用程序可在一个套接字上,接收以Windows消息为基础的网络事件通知。具体的做法是在建好一个套接字后,调用WSAAsyncSelect函数。该模型最早出现于Winsock的1.1版本中,用于帮助应用程序开发者面向一些早期的16位Windows平台(如WindowsforWorkgroups),适应其“落后”的多任务消息环境。应用程序仍可从这种模型中得到好处,特别是它们用一个标准的Windows例程(常称为WndProc),对窗口消息进行管理的时候。该模型亦得到了MicrosoftFoundationClass(微软基本类,MFC)对象CSocket的采纳。(节选自Windows网络编程第八章)我还是先贴出代码,然后做详细解释:#include#include#definePORT5150#defineMSGSIZE1024#defineWM_SOCKETWM_USER+0#pragmacomment(lib,ws2_32.lib)LRESULTCALLBACKWndProc(HWND,UINT,WPARAM,LPARAM);intWINAPIWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,PSTRszCmdLine,intiCmdShow)staticTCHARszAppName=_T(AsyncSelectModel);HWNDhwnd;MSGmsg;WNDCLASSwndclasswndclass.style=CS_HREDRAW|CS_VREDRAW;wndclass.lpfnWndProc=WndProc;wndclass.cbClsExtra=0;wndclass.cbWndExtra=0;wndclass.hInstance=hInstance;wndclass.hIcon=LoadIcon(NULL,IDI_APPLICATION);wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);wndclass.lpszMenuName=NULL;wndclass.lpszClassName=szAppName;if(!RegisterClass(&wndclass)MessageBox(NULL,TEXT(ThisprogramrequiresWindowsNT!),szAppName,MB_ICONERROR);return0;hwnd=CreateWindow(szAppName,/windowclassnameTEXT(AsyncSelectModel),/windowcaptionWS_OVERLAPPEDWINDOW,/windowstyleCW_USEDEFAULT,/initialxpositionCW_USEDEFAULT,/initialypositionCW_USEDEFAULT,/initialxsizeCW_USEDEFAULT,/initialysizeNULL,/parentwindowhandleNULL,/windowmenuhandlehInstance,/programinstancehandleNULL);/creationparametersShowWindow(hwnd,iCmdShow);UpdateWindow(hwnd);while(GetMessage(&msg,NULL,0,0)TranslateMessage(&msg);DispatchMessage(&msg);returnmsg.wParam;LRESULTCALLBACKWndProc(HWNDhwnd,UINTmessage,WPARAMwParam,LPARAMlParam)WSADATAwsd;staticSOCKETsListen;SOCKETsClient;SOCKADDR_INlocal,client;intret,iAddrSize=sizeof(client);charszMessageMSGSIZE;switch(message)caseWM_CREATE:/InitializeWindowsSocketlibraryWSAStartup(0x0202,&wsd);/CreatelisteningsocketsListen=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);/Bindlocal.sin_addr.S_un.S_addr=htonl(INADDR_ANY);local.sin_family=AF_INET;local.sin_port=htons(PORT);bind(sListen,(structsockaddr*)&local,sizeof(local);/Listenlisten(sListen,3);/AssociatelisteningsocketwithFD_ACCEPTeventWSAAsyncSelect(sListen,hwnd,WM_SOCKET,FD_ACCEPT);return0;caseWM_DESTROY:closesocket(sListen);WSACleanup();PostQuitMessage(0);return0;caseWM_SOCKET:if(WSAGETSELECTERROR(lParam)closesocket(wParam);break;switch(WSAGETSELECTEVENT(lParam)caseFD_ACCEPT:/AcceptaconnectionfromclientsClient=accept(wParam,(structsockaddr*)&client,&iAddrSize);/AssociateclientsocketwithFD_READandFD_CLOSEeventWSAAsyncSelect(sClient,hwnd,WM_SOCKET,FD_READ|FD_CLOSE);break;caseFD_READ:ret=recv(wParam,szMessage,MSGSIZE,0);if(ret=0|ret=SOCKET_ERROR&WSAGetLastError()=WSAECONNRESET)closesocket(wParam);elseszMessageret=0;send(wParam,szMessage,strlen(szMessage),0);break;caseFD_CLOSE:closesocket(wParam);break;return0;returnDefWindowProc(hwnd,message,wParam,lParam);在我看来,WSAAsyncSelect是最简单的一种WinsockI/O模型(之所以说它简单是因为一个主线程就搞定了)。使用RawWindowsAPI写过窗口类应用程序的人应该都能看得懂。这里,我们需要做的仅仅是:1.在WM_CREATE消息处理函数中,初始化WindowsSocketlibrary,创建监听套接字,绑定,监听,并且调用WSAAsyncSelect函数表示我们关心在监听套接字上发生的FD_ACCEPT事件;2.自定义一个消息WM_SOCKET,一旦在我们所关心的套接字(监听套接字和客户端套接字)上发生了某个事件,系统就会调用WndProc并且message参数被设置为WM_SOCKET;3.在WM_SOCKET的消息处理函数中,分别对FD_ACCEPT、FD_READ和FD_CLOSE事件进行处理;4.在窗口销毁消息(WM_DESTROY)的处理函数中,我们关闭监听套接字,清除WindowsSocketlibrary,下面这张用于WSAAsyncSelect函数的网络事件类型表可以让你对各个网络事件有更清楚的认识:FD_READ应用程序想要接收有关是否可读的通知,以便读入数据FD_WRITE应用程序想要接收有关是否可写的通知,以便写入数据FD_OOB应用程序想接收是否有带外(OOB)数据抵达的通知FD_ACCEPT应用程序想接收与进入连接有关的通知FD_CONNECT应用程序想接收与一次连接或者多点join操作完成的通知FD_CLOSE应用程序想接收与套接字关闭有关的通知FD_QOS应用程序想接收套接字“服务质量”(QoS)发生更改的通知FD_GROUP_QOS应用程序想接收套接字组“服务质量”发生更改的通知(现在没什么用处,为未来套接字组的使用保留)FD_ROUTING_INTERFACE_CHANGE应用程序想接收在指定的方向上,与路由接口发生变化的通知FD_ADDRESS_LIST_CHANGE应用程序想接收针对套接字的协议家族,本地地址列表发生变化的通知三.事件选择Winsock提供了另一个有用的异步I/O模型。和WSAAsyncSelect模型类似的是,它也允许应用程序在一个或多个套接字上,接收以事件为基础的网络事件通知。对于表1总结的、由WSAAsyncSelect模型采用的网络事件来说,它们均可原封不动地移植到新模型。在用新模型开发的应用程序中,也能接收和处理所有那些事件。该模型最主要的差别在于网络事件会投递至一个事件对象句柄,而非投递至一个窗口例程。(节选自Windows网络编程第八章)还是让我们先看代码然后进行分析:#include#include#definePORT5150#defineMSGSIZE1024#pragmacomment(lib,ws2_32.lib)intg_iTotalConn=0;SOCKETg_CliSocketArrMAXIMUM_WAIT_OBJECTS;WSAEVENTg_CliEventArrMAXIMUM_WAIT_OBJECTS;DWORDWINAPIWorkerThread(LPVOID);voidCleanup(intindex);intmain()WSADATAwsaData;SOCKETsListen,sClient;SOCKADDR_INlocal,client;DWORDdwThreadId;intiaddrSize=sizeof(SOCKADDR_IN);/InitializeWindowsSocketlibraryWSAStartup(0x0202,&wsaData);/CreatelisteningsocketsListen=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);/Bindlocal.sin_addr.S_un.S_addr=htonl(INADDR_ANY);local.sin_family=AF_INET;local.sin_port=htons(PORT);bind(sListen,(structsockaddr*)&local,sizeof(SOCKADDR_IN);/Listenlisten(sListen,3);/CreateworkerthreadCreateThread(NULL,0,WorkerThread,NULL,0,&dwThreadId);while(TRUE)/AcceptaconnectionsClient=accept(sListen,(structsockaddr*)&client,&iaddrSize);printf(Acceptedclient:%s:%dn,inet_ntoa(client.sin_addr),ntohs(client.sin_port);/Associatesocketwithnetworkeventg_CliSocketArrg_iTotalConn=sClient;g_CliEventArrg_iTotalConn=WSACreateEvent();WSAEventSelect(g_CliSocketArrg_iTotalConn,g_CliEventArrg_iTotalConn,FD_READ|FD_CLOSE);g_iTotalConn+;DWORDWINAPIWorkerThread(LPVOIDlpParam)intret,index;WSANETWORKEVENTSNetworkEvents;charszMessageMSGSIZE;while(TRUE)ret=WSAWaitForMultipleEvents(g_iTotalConn,g_CliEventArr,FALSE,1000,FALSE);if(ret=WSA_WAIT_FAILED|ret=WSA_WAIT_TIMEOUT)continue;index=ret-WSA_WAIT_EVENT_0;WSAEnumNetworkEvents(g_CliSocketArrindex,g_CliEventArrindex,&NetworkEvents);if(NetworkEvents.lNetworkEvents&FD_READ)/Receivemessagefromclientret=recv(g_CliSocketArrindex,szMessage,MSGSIZE,0);if(ret=0|(ret=SOC
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 土壤养分失衡矫正实施方案
- 燃气工程材料采购方案
- 雨水渗透池施工方案
- 校园围墙防攀爬安全教育
- XX市公共供水管网漏损治理工程项目工程方案
- 水库水资源调度优化方案
- 校园周边文明安全教育
- 铜采选工程施工方案
- 校园安全教育十二条
- 生物质能发电项目建设方案
- 2024广东省产业园区发展白皮书-部分1
- 2025年国家网络安全宣传周网络安全知识考核试题
- 2025四川蜀道建筑科技有限公司招聘16人备考练习题库及答案解析
- 生态视角下陕南乡村人居环境适老化设计初步研究
- 2025-2030中国教育领域的虚拟现实技术行业发展战略与应用趋势预测报告
- 2025广西现代物流集团第三次招聘109人笔试备考试题及答案解析
- 2025年中职历史考试题及答案
- 图书出口管理办法
- 高三后期班级管理课件
- 廉政教育进课堂大学
- GB/T 45777-2025水泥中石膏掺量评估方法
评论
0/150
提交评论