Windows Socket編程TCP範例之四(WSAEventSelect)

來源:互聯網
上載者:User
    Winsock提供了另一種有用的非同步事件通知 I/O 模型——WSAEventSelect模型。這個模型與WSAAsyncSelect模型類似,允許應用程式在一個或者多個通訊端上接收基於事件的網路通知。它與 WSAAsyncSelect模型類似是因為它也接收 FD_XXX 類型的網路事件,不過並不是依靠Windows 的訊息驅動機制,而是經由事件物件控點通知。     以下樣本還是實現和前兩篇文章(之一&之二&之三)一樣的功能:Client端串連Server端,向Server端發送資料。Server端接受Client端發送過來的資料並輸出。Server端還是單線程處理多Client端串連的情況。

Server.cpp-----------------------------

#include <iostream>#include <winsock2.h>#include <windows.h>using namespace std;#pragma comment(lib, "Ws2_32.lib")#define PORT_NO 6000#define BACKLOG 10// 記錄Socket及對應Event的數組及數組大小WSAEVENTeventArray[WSA_MAXIMUM_WAIT_EVENTS] = {0};SOCKETsockArray[WSA_MAXIMUM_WAIT_EVENTS] = {0};int nEventTotal = 0;// 請空序號為nIndex的數組元素:Socket以及Eventvoid ClearIndex(int nIndex);int main(int argc, char* argv[]){WSADATA wsaData;int ret;WORD wVersionRequested = MAKEWORD(2, 2);SOCKET sockSrv;SOCKADDR_IN addrSrv;// 初始化Windows Socket------ret = WSAStartup(wVersionRequested, &wsaData);if (ret != 0) {cout << "WSAStartup() failed:" << WSAGetLastError() << endl;return -1;}// 建立Socket------sockSrv = socket(AF_INET, SOCK_STREAM, 0);if (INVALID_SOCKET == sockSrv){cout << "socket() failed:" << WSAGetLastError() << endl;WSACleanup();return -1;}addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);addrSrv.sin_family = AF_INET;addrSrv.sin_port = htons(PORT_NO);// Bind Socket------ret = bind(sockSrv, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));if (SOCKET_ERROR == ret){cout << "bind() failed:" << WSAGetLastError() << endl;closesocket(sockSrv);WSACleanup();return -1;}// 監聽------ret = listen(sockSrv, BACKLOG);if (SOCKET_ERROR == ret){cout << "listen() failed:" << WSAGetLastError() << endl;closesocket(sockSrv);WSACleanup();return -1;}cout<< "Server started......" << endl;// 建立與sockSrv對應的WSAEvent並加入數組------WSAEVENT wsaEvt = WSACreateEvent();WSAEventSelect(sockSrv, wsaEvt, FD_ACCEPT | FD_CLOSE);eventArray[nEventTotal] = wsaEvt;sockArray[nEventTotal] = sockSrv;nEventTotal++;// Socket事件響應------while (1){int nIndex = WSAWaitForMultipleEvents(nEventTotal, eventArray, FALSE, WSA_INFINITE, FALSE);if (WSA_WAIT_FAILED == nIndex){cout << "WSAWaitForMultipleEvents failed:" << WSAGetLastError() << endl;break;}nIndex = nIndex - WSA_WAIT_EVENT_0;SOCKET sock = sockArray[nIndex];WSAEVENT wsaEvt = eventArray[nIndex];WSANETWORKEVENTS netWorkEvts;WSAEnumNetworkEvents(sock, wsaEvt, &netWorkEvts);if(netWorkEvts.lNetworkEvents & FD_ACCEPT)    // ---FD_ACCEPT{if(netWorkEvts.iErrorCode[FD_ACCEPT_BIT] == 0){SOCKADDR_IN  addrClient;int len = sizeof(SOCKADDR);SOCKET sockConn = accept(sock, (SOCKADDR*)&addrClient, &len);if (INVALID_SOCKET == sockConn)  {  cout << "accept() failed:" << WSAGetLastError() << endl;  continue;  }cout << "接受到新串連:" << inet_ntoa(addrClient.sin_addr) << endl;if(nEventTotal >= WSA_MAXIMUM_WAIT_EVENTS){cout << "Too many connections!" << endl;closesocket(sockConn);continue;}WSAEVENT sockConnEvt = WSACreateEvent();WSAEventSelect(sockConn, sockConnEvt, FD_READ | FD_CLOSE | FD_WRITE);eventArray[nEventTotal] = sockConnEvt;sockArray[nEventTotal] = sockConn;nEventTotal++;}}else if(netWorkEvts.lNetworkEvents & FD_READ)// ---FD_READ{if(netWorkEvts.iErrorCode[FD_READ_BIT] == 0){char recvBuffer[MAX_PATH] = {0};                    int ret = recv(sock, recvBuffer, sizeof(recvBuffer), 0);                  if (ret == 0)                    {cout << "Connection has been gracefully closed." << endl;                         closesocket(sock);  CloseHandle(wsaEvt);ClearIndex(nIndex);continue;                }                    else if (ret == SOCKET_ERROR)                     {                        cout << "Connection has been closed ungracefully." << endl;                         closesocket(sock); CloseHandle(wsaEvt);ClearIndex(nIndex);continue;                }                        cout << "Receive Data from Client:" << recvBuffer << endl;    }}else if(netWorkEvts.lNetworkEvents & FD_CLOSE)// ---FD_CLOSE{if(netWorkEvts.iErrorCode[FD_CLOSE_BIT] == 0){cout << "Connection has been gracefully closed." << endl;}else{cout << "Connection has been closed ungracefully." << endl;}closesocket(sock); CloseHandle(wsaEvt);ClearIndex(nIndex);}else if(netWorkEvts.lNetworkEvents & FD_WRITE)// ---FD_WRITE{}}// 清理資源------for (int i=0; i<nEventTotal; ++i){closesocket(sockArray[i]); CloseHandle(eventArray[i]);}WSACleanup();cout << "exit..." << endl;return 0;}// 請空序號為nIndex的數組元素:Socket以及Eventvoid ClearIndex(int nIndex){// 參數有效性檢查   0 =< nIndex <= WSA_MAXIMUM_WAIT_EVENTS-1if (nIndex < 0 || nIndex >= WSA_MAXIMUM_WAIT_EVENTS || nIndex >= nEventTotal)return;// 清空最後一個元素,則直接賦0if (nIndex == nEventTotal - 1){eventArray[nIndex] = 0;sockArray[nIndex] = 0;nEventTotal--;return;}    // 往前移for (int i=nIndex; i<=nEventTotal-2; ++i){eventArray[i] = eventArray[i+1];sockArray[i] = sockArray[i+1];nEventTotal--;}}

Client.cpp-----------------------------

#include <iostream>#include <windows.h>using namespace std;#pragma comment(lib, "Ws2_32.lib")#define PORT_NO 6000#define SRV_IP_ADDR "127.0.0.1"int main(int argc, char* argv[]){int ret;WSADATA wsaData;WORD wVersionRequested = MAKEWORD(2, 2);SOCKET sockClient;SOCKADDR_IN addrSrv;// 初始化Windows Socket------ret = WSAStartup(wVersionRequested, &wsaData);if (ret != 0) {cout << "WSAStartup() failed:" << WSAGetLastError() << endl;return -1;}    // 建立Socket------sockClient = socket(AF_INET, SOCK_STREAM, 0);if (INVALID_SOCKET == sockClient){cout << "socket() failed:" << WSAGetLastError() << endl;WSACleanup();return -1;}addrSrv.sin_addr.S_un.S_addr = inet_addr(SRV_IP_ADDR);addrSrv.sin_family = AF_INET;addrSrv.sin_port = htons(PORT_NO);// 串連------ret = connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));if (SOCKET_ERROR == ret){cout << "connect() failed:" << WSAGetLastError() << endl;closesocket(sockClient);WSACleanup();return -1;}else{cout << "connect() successfully." << endl;}// 發送資料------char sendBuf[MAX_PATH] = {0};while (1){cin.getline(sendBuf, sizeof(sendBuf));if (strcmp(sendBuf, "exit") == 0){break;}ret = send(sockClient, sendBuf, strlen(sendBuf)+1, 0);if (SOCKET_ERROR == ret){cout << "send() failed:" << WSAGetLastError() << endl;closesocket(sockClient);WSACleanup();return -1;}}// 清理資源-------closesocket(sockClient);WSACleanup();cout << "exit..." << endl;return 0;}
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.