[TCP/IP] ソケットのマルチタスク

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

}