5.6 accept()---"3490番ポートにコールいただきありがとうございます。"

accept() の呼び出しはちょっと変です。これから起こることはこうです。遠く離れた誰かが、あなたが listen() しているポートであなたのマシンに connect() しようとするでしょう。その接続は、accept() されるのを待つためにキューに入れられることになります。あなたは accept() をコールし、保留中の接続を取得するように指示します。すると、この接続に使用する新しいソケットファイル記述子が返されます!そうです、1つの値段で2つのソケットファイル記述子を手に入れたことになります。元のソケットファイル記述子はまだ新しい接続を待ち続けており、新しく作成されたソケットファイル記述子はようやく send()recv() を行う準備が整いました。着いたぞ!

書式は以下の通りです。

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

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

sockfdlisten() するソケット記述子です。簡単ですね。addr は通常、ローカルの struct sockaddr_storage へのポインタになります。この構造体には、着信接続に関する情報が格納されます(これにより、どのホストがどのポートからコールをかけてきたかを判断することができます)。addrlen はローカルの整数型変数で、そのアドレスが accept() に渡される前に sizeof(struct sockaddr_storage) に設定されなければなりません。accept() は、addraddrlen 以上のバイト数を入れることはありません。もし、それ以下のバイト数であれば、それを反映するように addrlen の値を変更します。

何だと思いますか?accept() はエラーが発生した場合は -1 を返し、errno をセットします。そうだったんですか。

前回と同様、一度に吸収するのは大変なので、サンプルコードの一部をご覧ください。

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

#define MYPORT "3490"  // the port users will be connecting to
#define BACKLOG 10     // how many pending connections queue will hold

int main(void)
{
    struct sockaddr_storage their_addr;
    socklen_t addr_size;
    struct addrinfo hints, *res;
    int sockfd, new_fd;

    // !! don't forget your error checking for these calls !!

    // first, load up address structs with getaddrinfo():

    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;  // use IPv4 or IPv6, whichever
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE;     // fill in my IP for me

    getaddrinfo(NULL, MYPORT, &hints, &res);

    // make a socket, bind it, and listen on it:

    sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
    bind(sockfd, res->ai_addr, res->ai_addrlen);
    listen(sockfd, BACKLOG);

    // now accept an incoming connection:

    addr_size = sizeof their_addr;
    new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &addr_size);

    // ready to communicate on socket descriptor new_fd!
    .
    .
    .

ここでも、すべての send()recv() の呼び出しに、ソケット記述子 new_fd を使用することに注意してください。もし、一度しか接続がないのであれば、同じポートからの接続を防ぐために、listen している sockfdclose() することができます。