(一)Socket I/Oモデルの選択(select)


回転元:クリックしてリンクを開く
Windowsプラットフォームでネットワークアプリケーションを構築するには、socket I/Oモデルを理解する必要があります.Windowsには、選択(select)、非同期選択(WSDAAsyncSelect)、イベント選択(WSOAEventSelect)、オーバーラップ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'
", 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
", 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.
", 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.クライアントの接続を受け入れます.