[TCP/IP] UDPサーバ

UDOの場合は、メッセージの境界を保持する。UDPはエラーから回復を行わないため、再送信に備えてバッファーを保持することがない。UDPソケットからsendto()を実行して処理が戻った時点で下位の送信チャンネルにメッセージが渡されるため、このタイミングでバッファからデータが出ていく。受信側ではバッファのサイズを十分に大きくして、データの破棄がなくなるようにしている。

#include <stdio.h> /* printf(), fprintf()に必要 */
#include <sys/socket.h> /* socket(), bind(), connect()に必要 */
#include <arpa/inet.h> /* sockaddr_in, inet_ntoaに必要 */
#include <stdlib.h> /* atoi()に必要 */
#include <string.h> /* memset()に必要 */
#include <unistd.h> /* close()に必要 */

#define ECHOMAX 255 /* エコー文字列の最大長 */

void DieWithError(char *errorMessage); /* エラー処理関数 */

int main(int argc, char *argv[]){
    int sock; /* ソケット */
    struct sockaddr_in echoServAddr; /* ローカルアドレス */
    struct sockaddr_in echoClntAddr; /* クライアントアドレス */
    unsigned int cliAddrLen; /* 着信メッセージの長さ */
    char echoBuffer[ECHOMAX]; /* エコー文字列用バッファ */
    unsigned short echoServPort; /* サーバのポート番号 */
    int recvMsgSize; /* 受信メッセージのサイズ */

    if(argc != 2) { /* 引数が正しいかの確認 */
        fprintf(stderr, "Usage: %s <Server Port\n>", argv[0]);
        exit(1);
    }

    echoServPort == atoi(argv[1]); /* ローカルポート */

    /* データグラムの送受信に使うソケットを作成 */
    if((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
        DieWithError("socket() failed");

    /* ローカルアドレス構造体を作成 */
    memset(&echoServAddr, 0, sizeof(echoServAddr)); /* 構造体を0埋め */
    echoServAddr.sin_family = AF_INET; /* インターネットアドレスファミリ */
    echoServAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* ワイルドカードを使用 */
    echoServAddr.sin_port = htons(echoServPort); /* ローカルポート */

    /* ローカルアドレスへのインバインド */
    if(bind(sock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0)
        DieWithError("bind() failed");

    /* 無限ループ */
    for(;;) {
        /* 入出力パラメータのサイズをセット */
        clntLen = sizeof(echoClntAddr);

        /* クライアントからメッセージを受信するまでブロックする */
        if((recvMsgSize = recvfrom(sock, echoBuffer, ECHOMAX, 0, (struct sockaddr *) &echoClntAddr, &cliAddrLen)) < 0)
            DieWithError("recvfrom() failed");

        printf("Handling client %s\n", inet_ntoa(echoClntAddr.sin_addr));

        /* 受信したデータグラムをクライアントに返信する */
        if(sendto(sock, echoBuffer, recvMsgSize, 0, (struct sockaddr *) &echoClntAddr, sizeof(echoClntAddr)) != recvMsgSize)
            DieWithError("sendto() sent a different number of bytes than expected");

    }
}