unix-socketプログラミングチートシート

/ Linux

ソケット通信プログラミングでよく使用するURLなどをまとめる。

manページ

クイックリファレンス(サーバ編)

凡例 最もよく見る記述

  • 第1引数の一言説明
  • 第2引数の一言説明
  • 戻り値の一言説明
sock = socket(AF_UNIX, SOCK_STREAM, 0);
  • AF_UNIX : プロセス間通信用ソケット。他にはAF_INET / AF_VSOCKなどが入る。
  • SOCK_STREAM : データ境界の概念がないストリームはコレ。そうでなければSOCK_SEQPACKET
  • 0 : 9割方使わない
  • sock : 失敗すると-1でerrnoを設定。
ret = bind(sock, (const struct sockaddr *) &addr, sizeof(addr));
  • sock : socketの返したもの。
  • addr : sockaddr_un構造体を指定。#include <sys/un.h>必要。
  • sizeof(addr) : サイズ。
  • ret : 成功で0、失敗で-1
struct sockaddr_un addr;

memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, path);

unlink(path);
if (bind(listenfd, (const struct sockaddr *) &addr, sizeof(addr)) < 0) {
    perror("bind");
    return -1;
}

構造体はこんな感じである。

ret = listen(sock, 10);
  • sock : socketが返してbind() 済みのもの。
  • 10 : backlogの数。acceptせずにためておける接続数。
fd = accept(sock, NULL, NULL);
  • sock : socketが返してbind() / listen() 済みのもの。
  • NULL×2 : 1個目はaddr, 2個目はsizeを示す、クライアントが設定するsockaddr構造体。見る必要がなければ両方NULL
  • fd : クライアントのfd。失敗は-1でerrno設定。
ret = recv(fd, buf, sizeof(buf), 0);
  • fd : accept()が返却のもの。
  • buf / sizeof(buf) : 受信バッファ。
  • 0 : フラグ。MSG_DONTWAIT / MSG_WAITALLなどを指定。
  • ret : 受信したバイト数。負値はエラー、0はクライアントが切断されたことを意味する。
ret = send(fd, buf, len, 0);
  • fd : accept()が返却のもの。
  • buf / len : 送信バッファ。
  • 0 : フラグ。MSG_DONTWAITなどを指定。
  • ret : 成功0、失敗-1。errno == ECONNRESETはクライアントが切断されたことを意味する。

クイックチェック(サーバ編)

前提

  • 2クライアント以上を受け付ける場合はfork() /pthread_create()による並列実行かpoll()`による多重化が必要です。
  • 1クライアントの場合でも切断前に新たなクライアントを受け付ける(accept())際は上記が必要です。
  • したがって「サーバ」と呼べるほとんどの実装ではマルチスレッドや多重化が必要になります。

チェック項目

というような背景からソケットプログラミング(特にサーバ)では多重化とマルチスレッドが必須となりどっちをやった場合でも抜け漏れが生じやすいです。

  • 多重化のためのpoll()accept()の発火を検知するためにsockそのものを入れ忘れていませんか?
  • accept()したfdを捨てていませんか?(クライアントが疎通できなくなる)
  • recv()の戻り値でクライアントの切断判定を行っていますか?
  • send()の戻り値でクライアントの切断判定を行っていますか?

おまけ:recv/sendread/writeの違いは何ですか?

第4引数のflagsを使わないかつSOCK_STREAMであれば違いありません。ただしread/writeのmanページからクライアントの切断判定を読み取るのは難しいでしょう。またSOCK_SEQPACKETなどは違いがあります。あきらめてrecv/sendを使用しましょう。

クイックリファレンス(クライアント編)

テストするためのプログラムであれば作成不要。

echo world | nc -q 0 -U socket

のような感じでsocketに文字を送信できる。-q 0を指定しないと切断せずにブロックしてしまうのでつけたほうが使いやすい。