WSAEventSelect编程模型实现

来源:互联网 发布:通天西游坐骑进阶数据 编辑:程序博客网 时间:2024/05/04 15:36

这篇代码的实现过程中参考了:

http://www.cppblog.com/yehao/articles/153729.html

http://fpcfjf.blog.163.com/blog/static/554697932011814102913/

http://blog.csdn.net/wanjingwei/article/details/4306609

服务器端:

//把#include <winsock2.h>放到最前面//至于原因,那是因为windows.h这个头文件已经包含了winsock.h //winsock.h和winsock2.h貌似有冲突 #include <Winsock2.h> #include <stdio.h>#include <Windows.h>//#include "winsock.h"//#pragma comment(lib,"wsock32")#pragma comment(lib,"Ws2_32")int main(){int accept_num = 0;int recv_num = 0;int send_num = 0;int close_num = 0;WSADATA wsadata;WORD version = MAKEWORD(2,2);int ret = WSAStartup(version,&wsadata);/*judge the right version of the windows socket*/if (ret != 0){printf("%s\n","socket create error!");return 0;}if (LOBYTE(wsadata.wVersion)!=2 || HIBYTE(wsadata.wVersion!=2)){printf("%s\n","socket version is error!");WSACleanup();return 0;}WSAEVENT eventArray[WSA_MAXIMUM_WAIT_EVENTS]; /*the array to store the event object*/SOCKET sockArray[WSA_MAXIMUM_WAIT_EVENTS];    /*the array to store the socket object*/int nEventTotal = 0;  /*the total number of the events*/USHORT nPort = 6000;/*create the listen socket and bind to specific port*/SOCKET sListen = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = htons(nPort);addr.sin_addr.S_un.S_addr = INADDR_ANY;ret = bind(sListen,(sockaddr *)&addr,sizeof(addr));if (SOCKET_ERROR == ret){printf("%s\n","socket bind error!");WSACleanup();return 0;}ret = listen(sListen,10);if (SOCKET_ERROR == ret){printf("%s\n","socket listen error!");WSACleanup();return 0;}//获取发送缓冲区和接受缓冲区的大小printf("%d\n",SO_MAX_MSG_SIZE);int recvbuf_len;int recvlength = sizeof(recvbuf_len);getsockopt(sListen,SOL_SOCKET,SO_RCVBUF,(char *)&recvbuf_len,&recvlength);printf("recvbuf is: %d\n",recvbuf_len);int sendbuf_len;int sendlength = sizeof(sendbuf_len);getsockopt(sListen,SOL_SOCKET,SO_SNDBUF,(char *)&sendbuf_len,&sendlength);printf("sendbuf is: %d\n",sendbuf_len);/*create a event object and bind it to a socket*/WSAEVENT Event = WSACreateEvent();  //注意需要手动重置事件或者使用可以重置事件的API操作//WSAEVENT Event = CreateEvent();//调用这个函数后,套接字被自动设置为非阻塞模式WSAEventSelect(sListen,Event,FD_ACCEPT|FD_CLOSE /*|FD_WRITE*/);//这样做是为了当网络时间发生时,确定是在哪个套接字上发生的。//之后就在这个套接字上做相应的操作。eventArray[nEventTotal] = Event;sockArray[nEventTotal] = sListen;nEventTotal++;/*deal with the network events*/while (true){//在所有事件对象上等待int nIndex = WSAWaitForMultipleEvents(nEventTotal,eventArray,false,WSA_INFINITE,false);//发生的事件对象的索引,一般是句柄数组中最前面的那一个,//然后再用循环依次处理后面的事件对象  nIndex = nIndex - WSA_WAIT_EVENT_0;//对每个事件调用WSAWaitForMultipleEvents函数,以便确定它的状态for (int i=nIndex; i<nEventTotal; i++){ret = WSAWaitForMultipleEvents(1,&eventArray[i],true,1000,false);if (WSA_WAIT_FAILED == ret || WSA_WAIT_TIMEOUT == ret){continue;}else{//获取到来的通知消息,WSAEnumNetworkEvents函数会自动重置受信事件  WSANETWORKEVENTS netEvent;WSAEnumNetworkEvents(sockArray[i],eventArray[i],&netEvent);if(netEvent.lNetworkEvents & FD_ACCEPT)  //处理FD_ACCEPT通知消息{accept_num++;printf("the accept number is: %d\n",accept_num);if(netEvent.iErrorCode[FD_ACCEPT_BIT]==0){if (nEventTotal > WSA_MAXIMUM_WAIT_EVENTS){printf("too many connections \n");continue;}SOCKET sNew = accept(sockArray[i],NULL,NULL);WSAEVENT Event1 = WSACreateEvent();WSAEventSelect(sNew,Event1,FD_READ|FD_CLOSE|FD_WRITE);eventArray[nEventTotal]=Event1;sockArray[nEventTotal]=sNew;nEventTotal++;}} else if (netEvent.lNetworkEvents & FD_READ)  //处理FD_READ通知消息 {recv_num++;printf("the receive number is: %d\n",recv_num);//注意,WSAEventselect模型是和I/O同步通信模型共同使用的//这个模型所说的非阻塞只是相对于阻塞模型中send时候无数据//发送或recv无数据接收等待而言的,具体当执行这两个函数的时候//和阻塞模型的执行过程是相同的,是I/O同步的。if(netEvent.iErrorCode[FD_READ_BIT]==0){char szText[8192];int nRecv = recv(sockArray[i],szText,sizeof(szText),0);printf("%d\n",nRecv);if (nRecv > 0){szText[nRecv]='\0';printf("message is : %s\n",szText);}}}else if (netEvent.lNetworkEvents & FD_CLOSE)  //处理FD_CLOSE通知消息 {close_num++;printf("the close number is: %d\n",close_num);accept_num--;if (netEvent.iErrorCode[FD_CLOSE_BIT]==0){closesocket(sockArray[i]);WSACloseEvent(eventArray[i]);for (int j=i;j<nEventTotal-1;j++){sockArray[j] = sockArray[j+1];eventArray[j] = eventArray[j+1];//sockArray[j] = sockArray[j+1];}nEventTotal--;}}else if (netEvent.lNetworkEvents & FD_WRITE){int ret_num;send_num++;printf("the send number is: %d\n",send_num);if (netEvent.iErrorCode[FD_WRITE_BIT] == 0){while (true){char msg[47368]="";ret_num = send(sockArray[i],msg,sizeof(msg),0);//ret_num += ret_num;//printf("   %d \n",ret_num);//这里是为了验证FD_WIRTE触发机制,在这里先填充满套接字缓冲区//让后在另一端recv,到一定程度后系统会提示可以继续发送,触发//该事件,具体多大空间可以是TCP协议定义的。if (ret_num == SOCKET_ERROR){if(WSAGetLastError() == WSAEWOULDBLOCK){printf("the buffer is full  \n");//Sleep(2000);break;}}}}}///////////////////////////////////////BEGIN/////////////////////////////////////////////这里是为了验证在同一套接字上的绑定的一个event,如果和这个event关联了//多个网络事件,当这多个网络事件同时发生的时候会不会由于处理了一个网络//事件之后重置了event导致另一个被屏蔽。这里利用在客户端send数据,在服务//器端调整处理FD_READ和FD_WRITE的处理顺序实验,说明会屏蔽的。/*else if (netEvent.lNetworkEvents & FD_READ)  //处理FD_READ通知消息 {recv_num++;printf("the receive number is: %d\n",recv_num);if(netEvent.iErrorCode[FD_READ_BIT]==0){char szText[256];int nRecv = recv(sockArray[i],szText,sizeof(szText),0);if (nRecv > 0){szText[nRecv]='\0';printf("message is : %s\n",szText);}}}////////////////////////////////////////END//////////////////////////////////////////*/}}}return 0;}


 

客户端:

#include <iostream>#include <stdio.h>#include <string>#include <Windows.h>#include "winsock.h"#pragma comment(lib, "wsock32")using namespace std;#define COMMAND 100int main(){int ret = 0;//初始化socket环境WSADATA wsadata;WORD version = MAKEWORD(2,0);ret = WSAStartup(version,&wsadata);//创建套接字并连接服务器SOCKET m_hClientSocket;m_hClientSocket = socket(AF_INET,SOCK_STREAM,0);SOCKADDR_IN m_addr1;m_addr1.sin_family = AF_INET;m_addr1.sin_addr.S_un.S_addr = inet_addr("192.168.100.57");m_addr1.sin_port = htons(6000);//在此可以测试FD_ACCEPT事件,以及第一次FD_WRITE事件触发机制ret = connect(m_hClientSocket,(LPSOCKADDR)&m_addr1,sizeof(m_addr1));//测试FD_READ事件触发机制char msg[1]="";if (send(m_hClientSocket,msg,sizeof(msg),0)==SOCKET_ERROR){break;}//测试FD_WRITE事件触发机制char Clisend_msg[10000]="";int recv_len;recv_len = recv(m_hClientSocket,Clisend_msg,sizeof(Clisend_msg),0);while (recv_len > 0){cout << recv_len << endl;recv_len = recv(m_hClientSocket,Clisend_msg,sizeof(Clisend_msg),0);}Sleep(10000);//测试FD_CLOSE事件触发机制closesocket(m_hClientSocket);WSACleanup();return 0;}


 

 

原创粉丝点击