🇯🇵 日本語 | 🇺🇸 English
広告スペース

C言語 ソケット通信入門

ネットワーク越しにデータをやり取りするプログラムをC言語で作る。

ソケット通信とは

ネットワーク上の2つのプログラムがデータを送受信するための仕組みがソケット(socket)です。Webブラウザ、メール、チャットなど、ネットワークを使うプログラムは全てソケット通信を行っています。
クライアント
あなたのプログラム

TCP/IP
インターネット
サーバー
Webサーバー等

TCP と UDP

TCP(信頼性あり)
データの到着を保証。順序も保証。
用途: Web, メール, ファイル転送
今回はこちらを使います
UDP(高速・軽量)
到着保証なし。順序保証なし。
用途: 動画配信, オンラインゲーム, DNS

必要なヘッダファイル

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>        // close()
#include <arpa/inet.h>     // inet_addr(), htons()
#include <netdb.h>         // gethostbyname()
#include <sys/socket.h>    // socket(), connect(), send(), recv()
注意: これらのヘッダは Linux / macOS で利用可能です。Windowsでは winsock2.h を使います。

ソケットAPIの流れ(クライアント側)

TCPクライアントがサーバーに接続してデータを送受信する手順は、以下の5ステップです。
1. socket() — ソケットを作成
2. connect() — サーバーに接続
3. send() — データを送信
4. recv() — データを受信
5. close() — ソケットを閉じる
電話に例えると: socket=電話機を用意、connect=相手にダイヤル、send/recv=話す/聞く、close=電話を切る

TCPクライアントを作る

実際にWebサーバーに接続してHTTPリクエストを送り、レスポンスを受け取るプログラムを作ります。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/socket.h>

#define BUF_SIZE 4096

int main(void) {
    const char *host = "example.com";
    int port = 80;

    // ===== 1. ホスト名をIPアドレスに解決 =====
    struct hostent *server = gethostbyname(host);
    if (server == NULL) {
        fprintf(stderr, "ホスト名の解決に失敗\n");
        return 1;
    }

    // ===== 2. ソケットを作成 =====
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        perror("socket");
        return 1;
    }

    // ===== 3. 接続先の情報を設定 =====
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);  // ポート番号(ネットワークバイトオーダー)
    memcpy(&addr.sin_addr.s_addr, server->h_addr, server->h_length);

    // ===== 4. サーバーに接続 =====
    if (connect(sockfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
        perror("connect");
        close(sockfd);
        return 1;
    }
    printf("接続成功: %s:%d\n\n", host, port);

    // ===== 5. HTTPリクエストを送信 =====
    char request[BUF_SIZE];
    snprintf(request, BUF_SIZE,
        "GET / HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n", host);
    send(sockfd, request, strlen(request), 0);

    // ===== 6. レスポンスを受信して表示 =====
    char buf[BUF_SIZE];
    int n;
    while ((n = recv(sockfd, buf, BUF_SIZE - 1, 0)) > 0) {
        buf[n] = '\0';
        printf("%s", buf);
    }

    // ===== 7. 切断 =====
    close(sockfd);
    printf("\n\n接続を閉じました\n");
    return 0;
}

コンパイルと実行

$ gcc http_client.c -o http_client $ ./http_client 接続成功: example.com:80 HTTP/1.1 200 OK Content-Type: text/html; charset=UTF-8 ... <html>...</html> 接続を閉じました

各関数の詳細解説

関数役割引数戻り値
socket()ソケットを作成AF_INET, SOCK_STREAM, 0ソケット記述子(int)
gethostbyname()ホスト名→IPアドレス"example.com"hostent構造体へのポインタ
connect()サーバーに接続sockfd, addr, addrlen0=成功, -1=失敗
send()データを送信sockfd, buf, len, flags送信バイト数
recv()データを受信sockfd, buf, len, flags受信バイト数(0=切断)
close()ソケットを閉じるsockfd0=成功
htons()ポート番号をネットワークバイトオーダーに変換ポート番号変換後のポート番号

sockaddr_in 構造体

struct sockaddr_in {
    short          sin_family;  // アドレスファミリ (AF_INET)
    unsigned short sin_port;    // ポート番号 (htons()で変換)
    struct in_addr sin_addr;    // IPアドレス
    char           sin_zero[8]; // パディング
};
htons = Host TO Network Short。 CPUのバイト順(リトルエンディアン等)とネットワークのバイト順(ビッグエンディアン)が異なるため、変換が必要です。

チャレンジ課題

課題1: 接続関数を分離する
上のプログラムの接続部分を int connect_to_server(const char *host, int port) 関数として切り出し、ソケット記述子を返すようにせよ。エラー時は -1 を返す。
課題2: 送受信関数を汎用化する
send_line / recv_line 関数を作り、1行ずつ送受信できるようにせよ。\r\n を自動付与する send_line と、\r\n まで読み取る recv_line。
課題3: コマンドライン引数でホストを指定
./http_client example.com 80 のように、ホスト名とポートをコマンドライン引数で渡せるようにせよ。argc/argvの講座を参照。
課題4: レスポンスをファイルに保存
受信したHTTPレスポンスをファイルに保存する機能を追加せよ。ファイル入出力の講座を参照。
次へ: SMTPメールクライアントを作る →
この記事をシェア
X(Twitter)でシェアはてブ

ネットワークプログラミングを深めるなら

ソケットの基礎を学んだら、書籍で体系的に学ぶと効果的です

📘
苦しんで覚えるC言語
MMGames 著
初心者向けの定番入門書。
Amazonで見る
📗
新・明解C言語 入門編
柴田望洋 著
図解が豊富で演習問題も充実。
Amazonで見る
📙
プログラミング言語C 第2版
B.W.カーニハン, D.M.リッチー 著
通称K&R。C言語の原典。
Amazonで見る

※ 上記リンクはアフィリエイトリンクです。購入によりサイト運営を支援いただけます。