DOKK / manpages / debian 10 / manpages-zh / accept.2.zh_TW
ACCEPT(2) Linux Programmer's Manual ACCEPT(2)

accept - 在一個套接字上接收一個連接

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

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

accept 函數用於基於連接的套接字 (SOCK_STREAM, SOCK_SEQPACKETSOCK_RDM). 它從未完成連接隊列中取出第一個連接請求,創建一個和參數 s 屬性相同的連接套接字,併爲這個套接字分配一個文件描述符, 然後以這個描述符返回.新創建的描述符不再處於傾聽狀態.原 套接字 s 不受此調用的影響.注意任意一個文件描述符標誌 (任何可以被 fcntl以參數 F_SETFL 設置的值,比如非阻塞式或者異步狀態)不會被 accept. 所繼承.

參數 s 是以 socket(2) 創建,用 bind(2) 綁定到一個本地地址,並且在調用了 listen(2). 之後正在偵聽一個連接的套接字. 參數 addr 是一個指向結構sockaddr的指針.這個結構體以連接實體地址填充. 所謂的連接實體,就是衆所周知的網絡層.參數 addr 所傳遞的真正的地址格式依賴於所使用的套接字族. (參見 socket(2) 和各協議自己的手冊頁). addrlen 是一個實時參數: 它的大小應該能夠足以容納參數 addr 所指向的結構體;在函數返回時此參數將以字節數表示出返回地址的 實際長度.若 addr 使用NULL作爲參數,addrlen將也被置爲NULL.

如果隊列中沒有未完成連接套接字,並且套接字沒有標記爲非阻塞式, accept 將阻塞直到一個連接到達.如果一個套接字被標記爲非阻塞式而隊列 中沒有未完成連接套接字, accept 將返回EAGAIN.

使用 select(2) 或者 poll(2). 可以在一個套接字上有連接到來時產生事件.當嘗試一個新的連接時 套接字讀就緒,這樣我們就可以調用 accept 爲這個連接獲得一個新的套接字.此外,你還可以設置套接字在喚醒時 接收到信號 SIGIO; 細節請參見 socket(7)

對於那些需要顯式確認的協議,比如 DECNet, accept 可以看作僅僅從隊列中取出下一個連接而不做確認.當在這個新的文件 描述符上進行普通讀寫操作時暗示了確認,當關閉這個新的套接字時暗 示了拒絕.目前在Linux上只有DECNet有這樣 的含義.

當接收到一個 SIGIO 信號或者 select(2)poll(2) 返回讀就緒並不總是意味着有新連接在等待,因爲連接可能在調用 accept 之前已經被異步網絡錯誤或者其他線程所移除.如果發生這種情況, 那麼調用將阻塞並等待下一個連接的到來.爲確保 accept 永遠不會阻塞,傳遞的套接字 s 需要置 O_NONBLOCK 標誌(參見 socket(7)).

此調用在發生錯誤時返回-1.若成功則返回一個非負整數標識這個 連接套接字.

Linux accept 將一個待處理網絡錯誤代碼通過 accept 傳遞給新套接字 . 這種處理方式有別於其他的BSD套接字實現.爲可靠操作,應用程序 必須在調用 accept 之後能夠檢測這些爲協議定義的網絡錯誤,並且以重試解決,就象 EAGAIN 一樣.對於TCP/IP這些網絡錯誤是 ENETDOWN, EPROTO, ENOPROTOOPT, EHOSTDOWN, ENONET, EHOSTUNREACH, EOPNOTSUPP, 以及 ENETUNREACH.

套接字被標記爲非阻塞,且當前沒有可接收的連接.
描述符非法.
描述符指向一個文件,而不是一個套接字.
作爲參數的套接字不是 SOCK_STREAM. 類型
參數 addr 不在用戶可寫地址空間之內.
防火牆規則禁止連接.
沒有足夠內存. 這個錯誤一般來說意味着內存分配受套接字緩衝區所限, 而不是沒有系統內存.

另外,新套接字和協議中定義的網絡錯誤也可能被返回. 不同的Linux內核也可能返回下列錯誤 EMFILE, EINVAL, ENOSR, ENOBUFS, EPERM, ECONNABORTED, ESOCKTNOSUPPORT, EPROTONOSUPPORT, ETIMEDOUT, ERESTARTSYS.

SVr4,4.4BSD( accept 函數首次出現於BSD 4.2). BSD手冊頁文檔定義了五個可能的錯誤返回值 (EBADF, ENOTSOCK, EOPNOTSUPP, EWOULDBLOCK, EFAULT). SUSv2文檔的定義是EAGAIN, EBADF, ECONNABORTED, EFAULT, EINTR, EINVAL, EMFILE, ENFILE, ENOBUFS, ENOMEM, ENOSR, ENOTSOCK, EOPNOTSUPP, EPROTO, EWOULDBLOCK.

Linux accept不繼承象 O_NONBLOCK 這樣的套接字標誌. 這一點有別於其他的BSD套接字實現. 因此,程序應該在accept所返回的套接字上設置所有需要的標誌.

函數 accept 的第三個參數原來被聲明爲'int *'(在libc4和libc5以及其他很多系統中, 比如BSD 4.*,SunOS 4, SGI);POSIX 1003.1g草案試圖將其改變爲 `size_t *',SunOS 5就是這麼做的. 後來的POSIX草案和Single Unix Specification以及glibc2使用了 `socklen_t *'. Quoting Linus Torvalds: 引自Linus Torvalds (譯註:這個傢伙就是Linux的創始人,所以我保留了他老人家的原文, 僅將原文大意附後): I fails: only italicizes a single line _Any_ sane library _must_ have "socklen_t" be the same size as int. Anything else breaks any BSD socket layer stuff. POSIX initially _did_ make it a size_t, and I (and hopefully others, but obviously not too many) complained to them very loudly indeed. Making it a size_t is completely broken, exactly because size_t very seldom is the same size as "int" on 64-bit architectures, for example. And it _has_ to be the same size as "int" because that's what the BSD socket interface is. Anyway, the POSIX people eventually got a clue, and created "socklen_t". They shouldn't have touched it in the first place, but once they did they felt it had to have a named type for some unfathomable reason (probably somebody didn't like losing face over having done the original stupid thing, so they silently just renamed their blunder).

數據類型"socklen_t"和int應該具有相同的長度.否則就會破壞 BSD套接字層的填充.POSIX開始的時候用的是size_t, Linus Torvalds(他希望有更多的人,但顯然不是很多) 努力向他們解釋使用size_t是完全錯誤的,因爲在64位結構中 size_t和int的長度是不一樣的,而這個參數(也就是accept函數 的第三參數)的長度必須和int一致,因爲這是BSD套接字接口 標準.最終POSIX的那幫傢伙找到了解決的辦法,那就是創造了 一個新的類型"socklen_t".Linux Torvalds說這是由於他們 發現了自己的錯誤但又不好意思向大家夥兒承認,所以另外 創造了一個新的數據類型.

bind(2), connect(2), listen(2), select(2), socket(2)

byeyear <love_my_love@263.net >

2002.01.27

《中國linux論壇man手冊頁翻譯計劃》:

http://cmpp.linuxforum.net

本頁面中文版由中文 man 手冊頁計劃提供。
中文 man 手冊頁計劃:https://github.com/man-pages-zh/manpages-zh

7 May 1999 Linux 2.2 Page