【C】ソケットAPIを用いたデータロガープログラムを書いてみる【socket】

こんにちは。
TCP/IP でのソケットを用いたデータ通信の仕組みに関して改めて勉強してみたので、自分自身の理解のために簡単なデータロガープログラムを書いてみました。
※ いつも通りエラーハンドリングは 無視 省力です。

client.c

まずはクライアント側ですね。
socket() でソケットを作成した後に、connect() を使えばコネクションが張れるようです。
後は生成したソケットを使って、send() でサーバ側にデータを送るだけです。
送信するデータは fgets() で標準入力から取得します。

#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(void){
    int sockfd;
    char mes[64];
    struct sockaddr_in server;

    server.sin_family = AF_INET;
    server.sin_port = htons(8888);
    server.sin_addr.s_addr = inet_addr("127.0.0.1");

    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    connect(sockfd, (struct sockaddr *)&server, sizeof(server));

    printf("INPUT:");
    fgets(mes, sizeof(mes), stdin);

    send(sockfd, mes, 64, 0);

    close(sockfd);

    return 0;
}

接続先サーバの情報は sockaddr_in 構造体を使って socket に紐づけます。
※ sockaddr にキャストする必要アリです。
例では localhost の 8888 ポートに接続しています。

server.c

次はサーバ側ですね。
サーバは bind() を使って ソケットに IPアドレス/ポート番号を紐づけ、listen() で割り当てたポート番号に接続を作成できることをシステムに伝えます。
※ 例では最大5つの接続を受け持ちます。( 後段の処理が完了するまで最大5つまでの接続要求がキューに入ります )
実際のデータの送受信にはこのソケットは用いず、accept() を使ってデータ送受信用のソケットを生成して処理を委任します。
後は recv() を使ってデータを受信し、ファイルにデータを書き込み データ送受信用のソケットをクローズします。
※ 36行目には到達しないです。

#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(void){
    int sock, sockfd, sock_size;
    char mes[64];
    struct sockaddr_in server;
    struct sockaddr_in client;
    FILE *file;

    server.sin_family = AF_INET;
    server.sin_port = htons(8888);
    server.sin_addr.s_addr = INADDR_ANY;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    bind(sockfd, (struct sockaddr *)&server, sizeof(server));

    listen(sockfd, 5);

    while(1){
        sock_size = sizeof(client);
        sock = accept(sockfd, (struct sockaddr *)&client, &sock_size);

        recv(sock, mes, 64, 0);
        file = fopen("loger.txt", "a");
        fprintf(file, mes);
        fclose(file);
        
        close(sock);
    }
    close(sockfd);
    return 0;
}

クライアントと同じく、受け持つIPアドレス/ポート番号を sockaddr_in 構造体を使って socket に紐づけます。
こちらも sockaddr にキャストする必要アリです。
※ INADDR_ANY は全ての接続元( 0.0.0.0 )を表しています。

まとめると下記の形になりますね。

1.socket() を実行して TCPソケットを作成する。
2.bind() を実行してソケットにポート番号(IPアドレスも)を割り当てる。
3.listen() を実行し割り当てたポート番号へ接続を作成できることをシステムに伝える。
4.以下繰り返し
・接続要求を受け取るたびに、accept() を呼び出して新規ソケットを取得
・作成したソケットを介してクライアント(接続要求元)とやり取り
・close() でクライアントとの接続をクローズ