Socket IO模型详解.doc_第1页
Socket IO模型详解.doc_第2页
Socket IO模型详解.doc_第3页
Socket IO模型详解.doc_第4页
Socket IO模型详解.doc_第5页
免费预览已结束,剩余32页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Socket I/O模型之选择(select) 在windows平台构建网络应用,必须了解socket I/O模型。windows提供了选择(select)、异步选择(WSAAsyncSelect)、事件选择(WSAEventSelect)、重叠I /O(overlapped I/O)和完成端口(completion port)。 一、客户端代码 C+代码 #includestdafx.h #include #include #pragmacomment(lib,ws2_32.lib) #defineSERVER_ADDRESS192.168.10.56 #definePORT5150 #defineMSGSIZE1024 intmain(intargc,char*argv) WSADATAwsaData; SOCKETsClient; SOCKADDR_INserver; charszMessageMSGSIZE; intret; /Initializewindowssocketlibrary WSAStartup(0x0202,&wsaData); /Createclientsocket sClient=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); /Connecttoserver memset(&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,(sockaddr*)&server,sizeof(SOCKADDR_IN); while(TRUE) printf(Send:); gets(szMessage); /Sendmessage send(sClient,szMessage,strlen(szMessage),0); /Receivemessage ret=recv(sClient,szMessage,MSGSIZE,0); szMessageret=0; printf(Received%dbytes:%sn,ret,szMessage); /Cleanup closesocket(sClient); WSACleanup(); return0; #include stdafx.h#include #include #pragma comment(lib, ws2_32.lib)#define SERVER_ADDRESS 192.168.10.56#define PORT 5150#define MSGSIZE 1024int main(int argc, char* argv)WSADATA wsaData;SOCKET sClient;SOCKADDR_IN server;char szMessageMSGSIZE;int ret;/ Initialize windows socket libraryWSAStartup(0x0202, &wsaData);/ Create client socketsClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);/ Connect to servermemset(&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, (sockaddr*)&server, sizeof(SOCKADDR_IN);while (TRUE) printf(Send:);gets(szMessage);/ Send messagesend(sClient, szMessage, strlen(szMessage), 0);/ Receive messageret = recv(sClient, szMessage, MSGSIZE, 0);szMessageret = 0;printf(Received %d bytes: %sn, ret, szMessage);/ Clean upclosesocket(sClient);WSACleanup();return 0;这是一个最简单的客户端代码,负责发送数据,然后接受返回。 二、使用select模型的服务器 C+代码 /writebylarry /2009-8-20 /Thisisserverusingselectmodel. #includestdafx.h #include #include #definePORT5150 #defineMSGSIZE1024 #pragmacomment(lib,ws2_32.lib) intg_iTotalConn=0; SOCKETg_CliSocketArrFD_SETSIZE; DWORDWINAPIWorkerThread(LPVOIDlpParam); intmain(intargc,char*argv) WSADATAwsaData; SOCKETsListen,sClient; SOCKADDR_INlocal,client; intiAddrSize=sizeof(SOCKADDR_IN); DWORDdwThreadId; /Initializewindowssocketlibrary WSAStartup(0x0202,&wsaData); /Createlisteningsocket sListen=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); /Bind local.sin_family=AF_INET; local.sin_addr.S_un.S_addr=htonl(INADDR_ANY); local.sin_port=htons(PORT); bind(sListen,(sockaddr*)&local,sizeof(SOCKADDR_IN); /Listen listen(sListen,3); /Createworkerthread CreateThread(NULL,0,WorkerThread,NULL,0,&dwThreadId); while(TRUE) /Acceptaconnection sClient=accept(sListen,(sockaddr*)&client,&iAddrSize); printf(Acceptedclient:%s:%dn,inet_ntoa(client.sin_addr),ntohs(client.sin_port); /Addsockettog_CliSocketArr g_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_CliSocketArri,&fdread); /Weonlycarereadevent ret=select(0,&fdread,NULL,NULL,&tv); if(ret=0) /Timeexpired continue; for(i=0;ig_iTotalConn;i+) if(FD_ISSET(g_CliSocketArri,&fdread) /Areadeventhappenedong_CliSocketArr ret=recv(g_CliSocketArri,szMessage,MSGSIZE,0); if(ret=0|(ret=SOCKET_ERROR&WSAGetLastError()=WSAECONNRESET) /Clientsocketclosed printf(Clientsocket%dclosed.n,g_CliSocketArri); closesocket(g_CliSocketArri); if(ig_iTotalConn-1) g_CliSocketArri-=g_CliSocketArr-g_iTotalConn; else /Wereveivedamessagefromclient szMessageret=0; send(g_CliSocketArri,szMessage,strlen(szMessage),0); / write by larry/ 2009-8-20/ This is server using select model.#include stdafx.h#include #include #define PORT 5150#define MSGSIZE 1024#pragma comment(lib, ws2_32.lib)int g_iTotalConn = 0;SOCKET g_CliSocketArrFD_SETSIZE;DWORD WINAPI WorkerThread(LPVOID lpParam);int main(int argc, char* argv)WSADATA wsaData;SOCKET sListen, sClient;SOCKADDR_IN local, client;int iAddrSize = sizeof(SOCKADDR_IN);DWORD dwThreadId;/ Initialize windows socket libraryWSAStartup(0x0202, &wsaData);/ Create listening socketsListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);/ Bindlocal.sin_family = AF_INET;local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);local.sin_port = htons(PORT);bind(sListen, (sockaddr*)&local, sizeof(SOCKADDR_IN);/ Listenlisten(sListen, 3);/ Create worker threadCreateThread(NULL, 0, WorkerThread, NULL, 0, &dwThreadId);while (TRUE) / Accept a connectionsClient = accept(sListen, (sockaddr*)&client, &iAddrSize);printf(Accepted client:%s:%dn, inet_ntoa(client.sin_addr), ntohs(client.sin_port);/ Add socket to g_CliSocketArrg_CliSocketArrg_iTotalConn+ = sClient;return 0;DWORD WINAPI WorkerThread(LPVOID lpParam)int i;fd_set fdread;int ret;struct timeval tv = 1, 0;char szMessageMSGSIZE;while (TRUE) FD_ZERO(&fdread);for (i = 0; i g_iTotalConn; i+) FD_SET(g_CliSocketArri, &fdread);/ We only care read eventret = select(0, &fdread, NULL, NULL, &tv);if (ret = 0) / Time expiredcontinue;for (i = 0; i g_iTotalConn; i+) if (FD_ISSET(g_CliSocketArri, &fdread) / A read event happened on g_CliSocketArrret = recv(g_CliSocketArri, szMessage, MSGSIZE, 0);if (ret = 0 | (ret = SOCKET_ERROR & WSAGetLastError() = WSAECONNRESET) / Client socket closedprintf(Client socket %d closed.n, g_CliSocketArri);closesocket(g_CliSocketArri);if (i g_iTotalConn-1) g_CliSocketArri- = g_CliSocketArr-g_iTotalConn; else / We reveived a message from clientszMessageret = 0;send(g_CliSocketArri, szMessage, strlen(szMessage), 0);这是异步模型中最简单的一种,服务器端的几个主要流程如下: 1.创建监听套接字,绑定,监听; 2.创建工作者线程; 3.创建一个套接字数组,用来存放当前所有活动的客户端套接字,每accept一个连接就更新一次数组; 4.接受客户端的连接。Socket I/O模型之异步选择(WSAAsyncSelect)使用异步选择模型,应用程序可在一个套接字上,接收以Windows消息为基础的网络事件通知。具体的做法是在建好一个套接字后,调用WSAAsyncSelect函数。 服务器端代码: C+代码 /writebylarry /2009-8-20 /ThisisaserverusingWSAAsyncSelectmodel. #includestdafx.h #include #include #definePORT5150 #defineMSGSIZE1024 #defineWM_SOCKETWM_USER+0 #pragmacomment(lib,ws2_32.lib) LRESULTCALLBACKWndProc(HWND,UINT,WPARAM,LPARAM); intAPIENTRYWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,LPSTRlpCmdLine,intnCmdShow) staticTCHARszAppName=_T(AsyncSelectModel); HWNDhwnd; MSGmsg; WNDCLASSwndclass; wndclass.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,_T(ThisprogramrequiresWindowsNT!),szAppName,MB_ICONERROR); return0; hwnd=CreateWindow(szAppName,/windowclassname _T(AsyncSelectModel),/windowcaption WS_OVERLAPPEDWINDOW,/windowstype CW_USEDEFAULT,/initialxpostion CW_USEDEFAULT,/initialypostion CW_USEDEFAULT,/initialxsize CW_USEDEFAULT,/initialysize NULL,/parentwindowhandle NULL,/windowmenuhandle hInstance,/programinstancehandle NULL);/creationparameters ShowWindow(hwnd,nCmdShow); UpdateWindow(hwnd); while(GetMessage(&msg,NULL,0,0) TranslateMessage(&msg); DispatchMessage(&msg); returnmsg.wParam; LRESULTCALLBACKWndProc(HWNDhwnd,UINTmessage,WPARAMwParam,LPARAMlParam) WSADATAwsaData; staticSOCKETsListen; SOCKETsClient; SOCKADDR_INlocal,client; intret,iAddrSize=sizeof(client); charszMessageMSGSIZE; switch(message) caseWM_CREATE: /Initializewindowssocketlibrary WSAStartup(0x0202,&wsaData); /Createlisteningsocket sListen=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); /Bind local.sin_family=AF_INET; local.sin_addr.S_un.S_addr=htonl(INADDR_ANY); local.sin_port=htons(PORT); bind(sListen,(sockaddr*)&local,sizeof(SOCKADDR_IN); /Listen listen(sListen,3); /AssociatelisteningsocketwithFD_ACCEPTevent WSAAsyncSelect(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: /Acceptaconnectionfromclient sClient=accept(wParam,(sockaddr*)&client,&iAddrSize); /AssociateclientsocketwithFD_READandFD_CLOSEevent WSAAsyncSelect(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); else szMessageret=0; send(wParam,szMessage,strlen(szMessage),0); break; caseFD_CLOSE: closesocket(wParam); break; return0; returnDefWindowProc(hwnd,message,wParam,lParam); / write by larry/ 2009-8-20/ This is a server using WSAAsyncSelect model.#include stdafx.h#include #include #define PORT 5150#define MSGSIZE 1024#define WM_SOCKET WM_USER+0#pragma comment(lib, ws2_32.lib)LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) static TCHAR szAppName = _T(AsyncSelect Model);HWND hwnd;MSG msg;WNDCLASS wndclass;wndclass.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, _T(This program requires Windows NT!), szAppName, MB_ICONERROR);return 0;hwnd = CreateWindow(szAppName, / window class name_T(AsyncSelect Model), / window captionWS_OVERLAPPEDWINDOW, / window stypeCW_USEDEFAULT, / initial x postionCW_USEDEFAULT, / initial y postionCW_USEDEFAULT, / initial x sizeCW_USEDEFAULT, / initial y sizeNULL, / parent window handleNULL, / window menu handlehInstance, / program instance handleNULL); / creation parametersShowWindow(hwnd, nCmdShow);UpdateWindow(hwnd);while (GetMessage(&msg, NULL, 0, 0)TranslateMessage(&msg);DispatchMessage(&msg);return msg.wParam;LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)WSADATA wsaData;static SOCKET sListen;SOCKET sClient;SOCKADDR_IN local, client;int ret, iAddrSize = sizeof(client);char szMessageMSGSIZE;switch (message)case WM_CREATE:/ Initialize windows socket libraryWSAStartup(0x0202, &wsaData);/ Create listening socketsListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);/ Bindlocal.sin_family = AF_INET;local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);local.sin_port = htons(PORT);bind(sListen, (sockaddr*)&local, sizeof(SOCKADDR_IN);/ Listenlisten(sListen, 3);/ Associate listening socket with FD_ACCEPT eventWSAAsyncSelect(sListen, hwnd, WM_SOCKET, FD_ACCEPT);return 0;case WM_DESTROY:closesocket(sListen);WSACleanup();PostQuitMessage(0);return 0;case WM_SOCKET:if (WSAGETSELECTERROR(lParam)closesocket(wParam);break;switch (WSAGETSELECTEVENT(lParam)case FD_ACCEPT:/ Accept a connection from clientsClient = accept(wParam, (sockaddr*)&client, &iAddrSize);/ Associate client socket with FD_READ and FD_CLOSE eventWSAAsyncSelect(sClient, hwnd, WM_SOCKET, FD_READ | FD_CLOSE);break;case FD_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;case FD_CLOSE:closesocket(wParam);break;return 0;return DefWindowProc(hwnd, message, wParam, lParam);服务器端得主要流程: 1.在WM_CREATE消息处理函数中,初始化Windows Socket library,创建监听套接字,绑定,监听,并且调用WSAAsyncSelect函数表示我们关心在监听套接字上发生的FD_ACCEPT事件; 2.自定义一个消息WM_SOCKET,一旦在我们所关心的套接字(监听套接字和客户端套接字)上发生了某个事件,系统就会调用WndProc并且message参数被设置为WM_SOCKET; 3.在WM_SOCKET的消息处理函数中,分别对FD_ACCEPT、FD_READ和FD_CLOSE事件进行处理; 4.在窗口销毁消息(WM_DESTROY)的处理函数中,我们关闭监听套接字,清除Windows Socket library 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 应用程序想接收针对套接字的协议家族,本地地址列表发生变化的通知 Socket I/O模型之事件选择(WSAEventSelect)WSAEventSelect和WSAAsyncSelect模型类似,它也允许应用程序在一个或多个套接字上,接收以事件为基础的网络事件通知。对于WSAAsyncSelect模型采用的网络事件来说,它们均可原封不动地移植到事件选择模型上。在用事件选择模型开发的应用程序中,也能接收和处理所有那些事件。该模型最主要的差别在于网络事件会投递至一个事件对象句柄,而非投递至一个窗口例程。 服务器端代码: C+代码 /writebylarry /2009-8-20 /ThisisaserverusingWSAEventSelectmodel. #includestdafx.h #include #include #pragmacomment(lib,ws2_32.lib) #definePORT5150 #defineMSGSIZE1024 intg_iTotalConn=0; SOCKETg_CliSocketArrMAXIMUM_WAIT_OBJECTS; WSAEVENTg_CliEventArrMAXIMUM_WAIT_OBJECTS; DWORDWINAPIWorkerThread(LPVOIDlpParam); voidCleanup(intindex); intmain(intargc,char

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论