プロセスやスレッドという仕組みを利用すれば、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;
}