(一)Socket I/O模型之选择(select)

来源:互联网 发布:amos软件什么意思 编辑:程序博客网 时间:2024/05/22 00:52

转自:点击打开链接


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

一、客户端代码 

#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模型的服务器 

// 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.接受客户端的连接。




原创粉丝点击