TCP サーバー
接続を受け付けます。
「TCP サーバー」はCoddyKit上の無料C Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C Academyコースには全4レッスンが含まれています。
TCPサーバーの構築
TCPサーバーはクライアントを待ち受け、接続を受け入れます。ライフサイクルは、ソケットを作成し、ポートにバインドし、待ち受けを開始してから、ループ内で接続を受け入れるという流れです。
ステップ1:ソケットを作成する
IPv4 TCP用のストリームソケットを作成します。負の値が返された場合は失敗です。
#include <sys/socket.h>
#include <stdio.h>
int make_server_socket(void) {
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0) { perror("socket"); }
return fd;
}ステップ2:アドレスの再利用を許可する
デフォルトでは、サーバー停止後もポートがTIME_WAIT状態で残り、再起動が妨げられます。setsockoptでSO_REUSEADDRを設定すると、すぐに再バインドできます。
#include <sys/socket.h>
void allow_reuse(int fd) {
int yes = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes);
}ステップ3:ポートにバインドする
bind()はソケットをローカルのアドレスとポートに関連付けます。INADDR_ANYを指定すると、すべてのネットワークインターフェースで待ち受けます。
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
int bind_port(int fd, unsigned short port) {
struct sockaddr_in addr = {0};
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port);
if (bind(fd, (struct sockaddr *)&addr, sizeof addr) < 0) {
perror("bind"); return -1;
}
return 0;
}ステップ4:待ち受ける
listen()はソケットをパッシブ状態(接続を受け入れられる状態)にします。バックログ引数は、カーネルがキューに入れられる保留中の接続数を設定します。
#include <sys/socket.h>
#include <stdio.h>
int start_listen(int fd) {
if (listen(fd, 16) < 0) { /* backlog of 16 */
perror("listen"); return -1;
}
return 0;
}ステップ5:接続を受け入れる
accept()はクライアントが接続するまでブロックし、そのクライアント用の新しいソケットを返します。元のソケットは待ち受けを続けます。
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
int accept_one(int listen_fd) {
struct sockaddr_in cli;
socklen_t len = sizeof cli;
int conn = accept(listen_fd, (struct sockaddr *)&cli, &len);
if (conn < 0) perror("accept");
return conn;
}2つのソケット、2つの役割
acceptの後には2つのソケットがあります。
- 待ち受け用ソケットは新しいクライアントを受け入れ続ける
- 接続用ソケットは特定の1クライアントと通信する
そのクライアントとの処理が終わったら、接続用ソケットを閉じてください。
リクエストを読み取る
recvを使って、クライアントのデータをバッファに読み込みます。戻り値が0の場合はクライアントが切断し、-1の場合はエラーです。
#include <sys/socket.h>
#include <stdio.h>
void handle(int conn) {
char buf[256];
ssize_t n = recv(conn, buf, sizeof buf - 1, 0);
if (n > 0) { buf[n] = 0; printf("got: %s\n", buf); }
}レスポンスを送信する
sendで応答します。大きなデータの場合は、1回の呼び出しでバッファの一部しか書き込めない可能性があるため、すべてのバイトを送信するまでループしてください。
#include <sys/socket.h>
#include <string.h>
void reply(int conn) {
const char *msg = "hello from server\n";
size_t left = strlen(msg);
const char *p = msg;
while (left > 0) {
ssize_t n = send(conn, p, left, 0);
if (n <= 0) break;
p += n; left -= (size_t)n;
}
}受け入れループ
単純な反復型サーバーは、1つのクライアントを受け入れて処理し、接続を閉じてから、次のクライアントを受け入れる処理に戻ります。クライアントを一度に1つずつ処理します。
#include <unistd.h>
void serve_loop(int listen_fd, int (*accept_one)(int), void (*handle)(int)) {
for (;;) {
int conn = accept_one(listen_fd);
if (conn < 0) continue;
handle(conn);
close(conn); /* done with this client */
}
}正常なシャットダウン
サーバーを停止するときは待ち受け用ソケットを閉じ、SIGINTを処理してループを正常に抜けます。カーネルのリソースを解放するため、ディスクリプタは必ず閉じてください。
理解度チェック
TCPサーバーについての理解度を確認しましょう。
まとめ
TCPサーバーを段階的に構築しました。
- socket、次にSO_REUSEADDR、bind、listen、acceptの順に呼び出す
acceptはクライアントごとの新しいソケットを返す- recv/sendで通信し、その後で接続を閉じる
- ループしてクライアントを処理し、すべての戻り値を確認する
よくある質問
「TCP サーバー」レッスンは無料ですか?
はい。「TCP サーバー」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C Academyコースには全4レッスンが含まれています。
「TCP サーバー」で何を学びますか?
接続を受け付けます。 ブラウザで直接実行するハンズオンコードでC Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
C Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのC Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。
「TCP サーバー」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このC Academyレッスンでコードを書いて実行できますか?
はい。すべてのC Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- ソケットの概要
- TCP サーバー
- TCP クライアント
- 複数クライアントの処理