Windows Socket編程TCP範例之三(WSAAsyncSelect)

來源:互聯網
上載者:User

        WSAAsyncSelect模型允許應用程式以Windows訊息的形式接收網路事件通知.這個模型是為了適應Windows的訊息驅動環境而設定的,現在許多對效能要求不高的網路應用程式都採用WSAAsyncSelect模型.MFC中的CSocket類也使用了它.

        以下樣本還是實現和前兩篇文章(之一&之二)一樣的功能:Client端串連Server端,向Server端發送資料。Server端接受Client端發送過來的資料並輸出。Server端還是單線程處理多Client端串連的情況。

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

1、在main中建立視窗但不調用ShowWindow即隱藏了視窗。由於是控制函程式,所以還是有控制函視窗的。

2、在ServerSocketProc中去初始化Windows Socket庫、建立Socket、綁定Socket、監聽Socket。

3、在視窗函數中處理Socket相關的訊息

4、Client端通過closesocket關閉通訊端會進入到以下的FD_CLOSE事件輸出:"FD_CLOSE"

而直接關閉Client端會使WSAGETSELECTERROR(lParam)為真,也就會輸出:"WSAGETSELECTERROR get error"

#include <windows.h>#include <iostream>using namespace std;LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);int ServerSocketProc(HWND);#pragma comment(lib, "Ws2_32.lib")    #define WM_SOCKET WM_USER + 100#define PORT_NO 6000  #define BACKLOG 10  // 全域變數SOCKET gSockSrv;int main(){static TCHAR lpszAppName[] = TEXT("TestWin");HWND      hwnd;MSG       msg;WNDCLASS  wc;wc.style         = CS_HREDRAW | CS_VREDRAW;wc.lpfnWndProc   = WndProc;wc.cbClsExtra    = 0;wc.cbWndExtra    = 0;wc.hInstance     = NULL;wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);wc.hCursor       = LoadCursor(NULL, IDC_ARROW);wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);wc.lpszMenuName  = NULL;wc.lpszClassName = lpszAppName;// 註冊視窗類別if (!RegisterClass(&wc)){MessageBox(NULL, TEXT("This program requires Windows NT!"),lpszAppName, MB_ICONERROR);return 0;}// 建立應用程式主視窗hwnd = CreateWindow(lpszAppName,TEXT("Server"),WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,NULL,NULL);if (NULL == hwnd){MessageBox(NULL, TEXT("CreateWindow failed."),lpszAppName, MB_ICONERROR);return 0;}// 建立Socket服務int ret = ServerSocketProc(hwnd);if (0 != ret){MessageBox(NULL, TEXT("ServerSocketProc failed."),lpszAppName, MB_ICONERROR);return 0;}// 訊息迴圈 while (GetMessage(&msg, NULL, 0, 0)){TranslateMessage(&msg);DispatchMessage(&msg);}    // 清理資源------  closesocket(gSockSrv);  WSACleanup();return msg.wParam;}//// 視窗過程函數//LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){switch (message){case WM_SOCKET:   // 處理Socket資訊{int ret;SOCKET sock = wParam;// 查看是否出錯if(WSAGETSELECTERROR(lParam)){closesocket(sock);cout << "WSAGETSELECTERROR get error" << endl;if (sock == gSockSrv){DestroyWindow(hwnd);}return 0;}// 處理髮生的事件switch(WSAGETSELECTEVENT(lParam)){case FD_ACCEPT:// 監聽中的通訊端檢測到有串連進入{int len=sizeof(SOCKADDR);SOCKADDR_IN addrClient;SOCKET sockConn = accept(sock, (SOCKADDR*)&addrClient, &len);if (INVALID_SOCKET == sockConn)                      {                          cout << "accept() failed:" << WSAGetLastError() << endl;                          return 0;                      }  cout << "接受到新串連:" << inet_ntoa(addrClient.sin_addr) << endl;WSAAsyncSelect(sockConn, hwnd, WM_SOCKET, FD_READ | FD_WRITE | FD_CLOSE);}break;case FD_WRITE:{}break;case FD_READ:{char recvBuffer[MAX_PATH] = {0};                      ret = recv(sock, recvBuffer, sizeof(recvBuffer), 0);if (ret == 0)                      {                          cout << "Connection has been gracefully closed." << endl;                           closesocket(sock);                          return 0;                      }                      else if (ret == SOCKET_ERROR)                       {                          cout << "Connection has been closed ungracefully." << endl;                           closesocket(sock);                          return 0;                      }                        cout << "Receive Data from Client:" << recvBuffer << endl;  }break;case FD_CLOSE:{ cout << "FD_CLOSE" << endl;closesocket(sock);}break;}}break;case WM_DESTROY:PostQuitMessage(0);return 0;}return DefWindowProc(hwnd, message, wParam, lParam);}int ServerSocketProc(HWND hwnd){cout << "ServerSocketProc-----------------------------------------BEG" << endl;WSADATA wsaData;int ret;WORD wVersionRequested = MAKEWORD(2, 2);SOCKET sockSrv;SOCKADDR_IN addrSrv;HANDLE hThread = NULL;// 初始化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;}gSockSrv = sockSrv;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;}// WSAAsyncSelect------WSAAsyncSelect(sockSrv, hwnd, WM_SOCKET, FD_ACCEPT | FD_CLOSE); cout << "ServerSocketProc-----------------------------------------END" << endl;cout<< "Server started......" << endl;return 0;}

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.