5.2 socket()---ファイル記述子を取得しよう!

もう先延ばしにはできません。socket() システムコールの話をしなければならないのです。以下はその書式です。

#include <sys/types.h>
#include <sys/socket.h>

int socket(int domain, int type, int protocol);

しかし、これらの引数は何なのでしょうか?これらは、どのようなソケットが欲しいか(IPv4 か IPv6 か、ストリームかデータグラムか、TCP か UDP か)を指定することができます。

以前は、これらの値をハードコードする人がいましたが、今でも絶対にそうすることができます。(ドメインは PF_INET または PF_INET6、タイプは SOCK_STREAM または SOCK_DGRAM、プロトコルは 0 に設定すると、与えられたタイプに適したプロトコルを選択することができます。あるいは getprotobyname() を呼んで、"tcp" や "udp" などの欲しいプロトコルを調べることもできます。)

(この PF_INET は、struct sockaddr_insin_family フィールドを初期化するときに使用できる AF_INET の近縁種です。実際、両者は非常に密接な関係にあり、実際に同じ値を持っているので、多くのプログラマは socket() を呼び出して PF_INET の代わりに AF_INET を第一引数に渡しています。さて、ミルクとクッキーを用意して、お話の時間です。昔々、あるアドレスファミリ(AF_INET の AF)が、プロトコルファミリ(PF_INET の PF)で参照される複数のプロトコルをサポートするかもしれないと考えられたことがあります。しかし、そうはなりませんでした。そして、みんな幸せに暮らした、ザ・エンド。というわけで、最も正しいのは struct sockaddr_inAF_INET を使い、socket() の呼び出しで PF_INET を使うことです。)

とにかく、もう十分です。本当にやりたいことは、getaddrinfo() の呼び出しの結果の値を使い、以下のように直接 socket() に送り込むことです。

int s;
struct addrinfo hints, *res;

// do the lookup
// [pretend we already filled out the "hints" struct]
getaddrinfo("www.example.com", "http", &hints, &res);

// again, you should do error-checking on getaddrinfo(), and walk
// the "res" linked list looking for valid entries instead of just
// assuming the first one is good (like many of these examples do).
// See the section on client/server for real examples.

s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);

socket() は単に、後のシステムコールで使用できるソケット記述子を返すか、エラーの場合は -1 を返します。グローバル変数 errno にはエラーの値が設定されます(詳細については errno のマニュアルページを参照してください。また、マルチスレッドプログラムで errno を使用する際の簡単な注意も参照してください。)

でも、このソケットは何の役に立つのでしょうか?答えは、これだけでは本当に意味がなく、もっと読み進めてシステムコールを作らないと意味がないのです。