ACCEPT(2) | Linux Programmer's Manual | ACCEPT(2) |
名前
accept, accept4 -ソケットへの接続を受ける書式
#include <sys/types.h> /* 「注意」参照 */
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
#define _GNU_SOURCE /* feature_test_macros(7) 参照 */
#include <sys/socket.h>
int accept4(int sockfd, struct sockaddr *addr,
socklen_t *addrlen, int flags);
説明
accept() システムコールは、接続指向のソケット型 ( SOCK_STREAM, SOCK_SEQPACKET) で用いられる。この関数は、接続待ちソケット socket 宛ての保留状態の接続要求が入っているキューから先頭の接続要求を取り出し、接続済みソケットを新規に生成し、そのソケットを参照する新しいファイル・ディスクリプタを返す。新規に生成されたソケットは、接続待ち (listen) 状態ではない。もともとのソケット sockfd はこの呼び出しによって影響を受けない。引き数 sockfd は、 socket(2) によって生成され、 bind(2) によってローカルアドレスにバインドされ、 listen(2) を経て接続を待っているソケットである。
addr 引き数は sockaddr 構造体へのポインタである。この構造体には接続相手のソケットのアドレスが入っている。 addr 引き数で返されるアドレスの正確なフォーマットは、ソケットのアドレス種別によって変わる ( socket(2) およびそれぞれのプロトコルの man ページを参照)。 addr が NULL の場合、 addr には何も入らない。この場合、 addrlen は使用されず、この引き数は NULL にしておくべきである。
addrlen 引き数は入出力両用の引き数である。呼び出し時には、呼び出し元が addr が指す構造体のサイズ (バイト単位) で初期化しておかなければならない。返ってくる時には、接続相手のアドレスの実際の大きさが格納される。
渡されたバッファが小さ過ぎた場合は、返されるアドレスの末尾が切り詰められる。この場合には、 addrlen には、呼び出し時に指定された値よりも大きな値が格納される。
キューに保留となっている接続要求がなく、かつソケットが非停止になっていないときは、 accept() は接続が発生するまで呼び出し元を停止 (block) する。ソケットが非停止になっていて、待ち状態の接続要求がキューに無いときは、 accept() はエラー EAGAIN か EWOULDBLOCK で失敗する。
ソケットへの接続到着を知るには、 select(2) または poll(2) を用いればよい。新しい接続要求が来るとソケットは読み込み可能になるので、そうしたら accept() を呼んでその接続に対するソケットを取得すればよい。あるいはソケットに設定を行い、何らかのアクションがあったときに SIGIO を配送 (deliver) させるようにすることもできる。詳細は socket(7) を参照のこと。
明示的な接続確認 (confirmation) を必要とするようなプロトコル (DECNet など) では、 accept() は単に次の接続要求をキューから取り出すだけであり、接続確認は行わないことに注意せよ。接続確認は、新しいファイル・ディスクリプタに対する通常の読み取り/書き込みによってなされ、接続拒否 (rejection) は新しいソケットをクローズすることによってなされる。現在のところ、 Linux 上でこれらのセマンティクスを持つのは DECNet だけである。
flags が 0 の場合、 accept4() は accept() と同じである。 flags に以下の値をビット毎の論理和 (OR) で指定することで、異なる動作をさせることができる。
- SOCK_NONBLOCK
- 新しく生成されるオープンファイル記述 (open file description) の O_NONBLOCK ファイルステータスフラグをセットする。このフラグを使うことで、 O_NONBLOCK をセットするために fcntl(2) を追加で呼び出す必要がなくなる。
- SOCK_CLOEXEC
- 新しいファイルディスクリプタに対して close-on-exec ( FD_CLOEXEC) フラグをセットする。このフラグが役に立つ理由については、 open(2) の O_CLOEXEC フラグの説明を参照のこと。
返り値
成功した場合、これらのシステムコールは受け付けたソケットのディスクリプタである非負の整数値を返す。エラーが発生した場合は-1 を返し、 errno を適切に設定する。エラー処理
Linux の accept() (と accept4()) は、新しいソケットにおける、発生済みのネットワークエラーを accept() からのエラーコードとして渡す。この振舞いは BSD ソケットの実装とは異なる。信頼性の高い動作を行うためには、アプリケーションはプロトコルで定義されているネットワークエラーの検知を accept() のあとに行い、それらのエラーを EAGAIN と同じように扱い、再試行 (retry) を行うべきである。 TCP/IP では、以下のエラーが該当する: ENETDOWN, EPROTO, ENOPROTOOPT, EHOSTDOWN, ENONET, EHOSTUNREACH, EOPNOTSUPP, ENETUNREACHエラー
- EAGAIN または EWOULDBLOCK
- ソケットが非停止になっていて、かつ受付け対象の接続が存在しない。 POSIX.1-2001 は、この場合にどちらのエラーを返すことも認めており、これら 2 つの定数が同じ値を持つことも求めていない。したがって、移植性が必要なアプリケーションでは、両方の可能性を確認すべきである。
- EBADF
- ディスクリプタが不正。
- ECONNABORTED
- 接続が中止された。
- EFAULT
- addr 引き数がユーザアドレス空間の書き込み可能領域にない。
- EINTR
- 有効な接続が到着する前に捕捉されたシグナルによってシステムコールが中断された。 signal(7) 参照。
- EINVAL
- ソケットが接続待ち状態ではない。もしくは、 addrlen が不正である (例えば、負の場合など)。
- EINVAL
- ( accept4()) flags に不正な値が指定されている。
- EMFILE
- 1プロセスがオープンできるファイル・ディスクリプタ数の上限に達した。
- ENFILE
- オープンされたファイルの総数がシステム全体の上限に達していた。
- ENOBUFS, ENOMEM
- メモリが足りない。多くの場合は、システムメモリが足りないわけではなく、ソケットバッファの大きさによるメモリ割り当ての制限である。
- ENOTSOCK
- ディスクリプタはソケットではなくファイルを参照している。
- EOPNOTSUPP
- 参照しているソケットの型が SOCK_STREAM でない。
- EPROTO
- プロトコル・エラー。
上記に加えて、Linux の accept() は以下のエラーで失敗する:
- EPERM
- ファイアウォールのルールにより接続が禁止された。
この他に、新しいソケットに対するネットワークエラーが返されることもある。これらはそれぞれのプロトコルで定義されている。いろいろな Linux カーネルでは、以下に示すようなエラーを返すこともある。 ENOSR, ESOCKTNOSUPPORT, EPROTONOSUPPORT, ETIMEDOUT. ERESTARTSYS がトレースの最中に現れることもある。
バージョン
accept4() システムコールは Linux 2.6.28 以降で利用可能である。 glibc でのサポートはバージョン 2.10 以降で利用可能である。準拠
accept(): POSIX.1-2001, SVr4, 4.4BSD, ( accept() は 4.2BSD で初めて実装された).Linux では、 accept() が返す新しいソケットは listen を行っているソケットのファイル状態フラグ ( O_NONBLOCK や O_ASYNC など) を継承「しない」。この動作は標準的な BSD ソケットの実装とは異なっている。移植性を考慮したプログラムではファイル状態フラグが継承されるかどうかは前提にせず、常に accept() が返したソケットに対して全ての必要なフラグを明示的に設定するようにすべきである。
注意
POSIX.1-2001 では <sys/types.h> のインクルードは必須とされておらず、 Linux ではこのヘッダファイルは必要ではない。しかし、歴史的には、いくつかの実装 (BSD 系) でこのヘッダファイルが必要であり、移植性が必要なアプリケーションではこのファイルをインクルードするのが賢明であろう。socklen_t 型
accept() の第 3 引き数は、もともと int * と宣言されていた (libc4 や libc5, 4.x BSD, SunOS 4, SGI など多くのシステムではそうなっている)。 POSIX.1g draft 標準は、これを size_t * に変更しようとし、SunOS 5 ではそう宣言されている。後に POSIX drafts には socklen_t * が含まれるようになり、 Single UNIX Specification や glibc2 ではこのように宣言されるようになった。 Linus Torvald の発言を引用する:例
bind(2) 参照。関連項目
bind(2), connect(2), listen(2), select(2), socket(2), socket(7)この文書について
この man ページは Linux man-pages プロジェクトのリリース 3.51 の一部である。プロジェクトの説明とバグ報告に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。2010-09-10 | Linux |