select模型使用例子

    技术2025-12-19  9

    在windows平台构建网络应用,必须了解socket I/O模型。windows提供了选择(select)、异步选择(WSAAsyncSelect)、事件选择(WSAEventSelect)、重叠I /O(overlapped I/O)和完成端口(completion port)。 一、客户端代码

    C++代码 #include "stdafx.h"   #include <WINSOCK2.H>   #include <stdio.h>   #pragma comment(lib, "ws2_32.lib")   #define SERVER_ADDRESS  "192.168.10.56"   #define PORT  5150   #define MSGSIZE  1024   int main(int argc, char* argv[])   {       WSADATA wsaData;       SOCKET sClient;       SOCKADDR_IN server;       char szMessage[MSGSIZE];       int ret;       // Initialize windows socket library       WSAStartup(0x0202, &wsaData);       // Create client socket       sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);       // Connect to server       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);           // Send message           send(sClient, szMessage, strlen(szMessage), 0);           // Receive message           ret = recv(sClient, szMessage, MSGSIZE, 0);           szMessage[ret] = '/0';           printf("Received [%d bytes]: '%s'/n", ret, szMessage);       }       // Clean up       closesocket(sClient);       WSACleanup();       return 0;   }   #include "stdafx.h" #include <WINSOCK2.H> #include <stdio.h> #pragma comment(lib, "ws2_32.lib") #define SERVER_ADDRESS "192.168.10.56" #define PORT 5150 #define MSGSIZE 1024 int main(int argc, char* argv[]) { WSADATA wsaData; SOCKET sClient; SOCKADDR_IN server; char szMessage[MSGSIZE]; int ret; // Initialize windows socket library WSAStartup(0x0202, &wsaData); // Create client socket sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // Connect to server 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); // Send message send(sClient, szMessage, strlen(szMessage), 0); // Receive message ret = recv(sClient, szMessage, MSGSIZE, 0); szMessage[ret] = '/0'; printf("Received [%d bytes]: '%s'/n", ret, szMessage); } // Clean up closesocket(sClient); WSACleanup(); return 0; }

    这是一个最简单的客户端代码,负责发送数据,然后接受返回。 二、使用select模型的服务器

    C++代码 // write by larry   // 2009-8-20   // This is server using select model.   #include "stdafx.h"   #include <winsock.h>   #include <stdio.h>   #define PORT  5150   #define MSGSIZE  1024   #pragma comment(lib, "ws2_32.lib")   int g_iTotalConn = 0;   SOCKET g_CliSocketArr[FD_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 library       WSAStartup(0x0202, &wsaData);       // Create listening socket       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);       // Create worker thread       CreateThread(NULL, 0, WorkerThread, NULL, 0, &dwThreadId);       while (TRUE)        {           // Accept a connection           sClient = accept(sListen, (sockaddr*)&client, &iAddrSize);           printf("Accepted client:%s:%d/n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));           // Add socket to g_CliSocketArr           g_CliSocketArr[g_iTotalConn++] = sClient;       }       return 0;   }   DWORD WINAPI WorkerThread(LPVOID lpParam)   {       int i;       fd_set fdread;       int ret;       struct timeval tv = {1, 0};       char szMessage[MSGSIZE];       while (TRUE)        {           FD_ZERO(&fdread);           for (i = 0; i < g_iTotalConn; i++)            {               FD_SET(g_CliSocketArr[i], &fdread);           }           // We only care read event           ret = select(0, &fdread, NULL, NULL, &tv);           if (ret == 0)            {               // Time expired               continue;           }           for (i = 0; i < g_iTotalConn; i++)            {               if (FD_ISSET(g_CliSocketArr[i], &fdread))                {                   // A read event happened on g_CliSocketArr                   ret = recv(g_CliSocketArr[i], szMessage, MSGSIZE, 0);                   if (ret == 0 || (ret == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET))                    {                       // Client socket closed                       printf("Client socket %d closed./n", g_CliSocketArr[i]);                       closesocket(g_CliSocketArr[i]);                       if (i < g_iTotalConn-1)                        {                           g_CliSocketArr[i--] = g_CliSocketArr[--g_iTotalConn];                       }                   }                    else                    {                       // We reveived a message from client                       szMessage[ret] = '/0';                       send(g_CliSocketArr[i], szMessage, strlen(szMessage), 0);                   }               }           }       }   }   // write by larry // 2009-8-20 // This is server using select model. #include "stdafx.h" #include <winsock.h> #include <stdio.h> #define PORT 5150 #define MSGSIZE 1024 #pragma comment(lib, "ws2_32.lib") int g_iTotalConn = 0; SOCKET g_CliSocketArr[FD_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 library WSAStartup(0x0202, &wsaData); // Create listening socket 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); // Create worker thread CreateThread(NULL, 0, WorkerThread, NULL, 0, &dwThreadId); while (TRUE) { // Accept a connection sClient = accept(sListen, (sockaddr*)&client, &iAddrSize); printf("Accepted client:%s:%d/n", inet_ntoa(client.sin_addr), ntohs(client.sin_port)); // Add socket to g_CliSocketArr g_CliSocketArr[g_iTotalConn++] = sClient; } return 0; } DWORD WINAPI WorkerThread(LPVOID lpParam) { int i; fd_set fdread; int ret; struct timeval tv = {1, 0}; char szMessage[MSGSIZE]; while (TRUE) { FD_ZERO(&fdread); for (i = 0; i < g_iTotalConn; i++) { FD_SET(g_CliSocketArr[i], &fdread); } // We only care read event ret = select(0, &fdread, NULL, NULL, &tv); if (ret == 0) { // Time expired continue; } for (i = 0; i < g_iTotalConn; i++) { if (FD_ISSET(g_CliSocketArr[i], &fdread)) { // A read event happened on g_CliSocketArr ret = recv(g_CliSocketArr[i], szMessage, MSGSIZE, 0); if (ret == 0 || (ret == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET)) { // Client socket closed printf("Client socket %d closed./n", g_CliSocketArr[i]); closesocket(g_CliSocketArr[i]); if (i < g_iTotalConn-1) { g_CliSocketArr[i--] = g_CliSocketArr[--g_iTotalConn]; } } else { // We reveived a message from client szMessage[ret] = '/0'; send(g_CliSocketArr[i], szMessage, strlen(szMessage), 0); } } } } }

    这是异步模型中最简单的一种,服务器端的几个主要流程如下: 1.创建监听套接字,绑定,监听; 2.创建工作者线程; 3.创建一个套接字数组,用来存放当前所有活动的客户端套接字,每accept一个连接就更新一次数组; 4.接受客户端的连接。

    最新回复(0)