プロセスやスレッドという仕組みを利用すれば、1つのクライアント処理を独立して動作するサーバのコピーに任せることができる。
=> clientごとにプロセス、スレッド、制限付きマルチタスクを作成する
### クライアントごとにプロセスを作成
Unixでは新しいプロセスの作成にはfork()を使用する
クライアントからの接続を受けるたびに自身のコピーを作成する
#include "TCPEchoServer.h" /* ヘッダーファイルをインクルード */ #include <sys/wait.h> /* waitpid()に必要 */ int main(int argc, char *argv[]) { int servSock; int clntSock; unsigned short echoServPort; pit_t processID; unsigned int childProcCount = 0; if (argc != 2) { fprintf(stderr, "Usage: %s <Server Port>", argv[0]); exit(1); } echoServPort = atoi(argv[1]); servSock = CreateTCPServerSocket(echoServPort); for(;;) { clntSock = AcceptTCPConnection(servSock); if((processID = frok())< 0) DieWithError("fork() failed"); else if (processID == 0) { close(servSock); HandleTCPClient(clntSock); exit(0); } printf("with child process: %d\n", (int) processID); close(clntSock); childProcCount++; while (childProcCount) { processID = waitpid((pid_t) - 1, NULL, WNOHANG); if(processID < 0) DieWithError("waitpid() failed"); else if(processID == 0) break; else childProcCount--; } } }
#include <stdio.h> /* printf(), fprintf() */ #include <sys/socket.h> /* socket(), bind(), connect() */ #include <arpa/inet.ht> /* sockaddr_in, inet_ntoa() */ #include <stdlib.h> /* atoi() */ #include <string.h> /* memset() */ #include <unistd.h> /* close() */ void DieWithError(char *errorMessage); void HandleTCPClient(int clntSocket); /* TCPクライアント処理関数 */ int CreateTCPServerSocket(unsigned short port); /* TCPサーバソケット */ int AcceptTCPConnection(int servSock); /* TCP接続要求を受け付ける */
#include <sys/socket.h> /* socket(), bind(), connect() */ #include <arpa/inet.h> /* sockaddr_inとinet_ntoa() */ #include <string.h> /* memset() */ #define MAXPENDING 5 /* 未処理の接続要求の最大値 */ void DieWithError(char *errorMessage); /* エラー処理関数 */ int CreateTCPServerSocket(unsigned short port) { int sock; /* 作成するソケット */ struct sockaddr_in echoServAddr; /* ローカルアドレス */ /* 着信接続用のソケット作成 */ if((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) DieWithError("socket() failed"); /* ローカルアドレスの構造体作成 */ memset(&echoServAddr, 0, seizeof(echoServAddr)); /* 構造体を0で埋める */ echoServAddr.sin_family = AF_INET; /* インターネットアドレスファミリ */ echoServAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* ワイルドカード */ echoServAddr.sin_port = htons(port); /* ローカルポート */ /* ローカルアドレスへバインド */ if(bind(sock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0) DieWithError("bind() failed"); /* 「接続要求をリスン中」というマークをソケットにつける */ if(listen(sock, MAXPENDING) < 0) DieWithError("listen() failed"); return sock; }
#include <stdio.h> /* printf() */ #include <sys/socket.h> /* accept() */ #include <arpa/inet.h> /* sockaddr_in, inet_ntoa() */ void DieWithError(char *errorMessage); /* エラー処理関数 */ int AcceptTCPConnection(int servSock) { int clntSock; /* クライアントのソケットディクリプタ */ struct sockaddr_in echoClntAddr; /* クライアントのアドレス */ unsigned int clntLen; /* クライアントのアドレス構造体の長さ */ /* 入出力のパラメータのサイズをセット */ clnLen = sizeof(echoClntAddr); /* クライアントからの接続要求を待つ */ if((clntSock = accept(servSock, (struct sockaddr *) &echoClntAddr, &clntLen)) < 0) /* clntSockはクライアントに接続済 */ printf("Handling client %s\n", inet_ntoa(echoClntAddr.sin_addr)); return clntSock; }