ACCEPT()和ACCEPT4()
ACCEPT
章節:Linux 程序員手冊 (2)更新:2010-09-10
到 易美翻譯 翻譯
名字
accept - 通過套接口接受一個連接概要
#include Esys/types.h> /* 參看 “注意小節” */ #include Esys/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)。它取出在監聽套接口 sockfd請求隊列里的第一個連接,新建一個已連接的套接口,并且返回一個引用該套接口新的文件描述符。新建的套接口不處于監聽狀態。原始的套接口 sockfd 沒有受到影響。參數 sockfd 是一個由 socket(2) 創建的套接口,通過 bind綁定到一個本地地址,并且在調用 listen(2)之后正處于監聽之中。
參數 addr 是指向一個 sockaddr結構的指針。這結構體被填充為一個端套接口,又被稱為通信層。返回的地址結體 addr的額外的格式可以通過套接口地址族(參看 socket(2)和各自的協議手冊頁)來確定。當 addr 是 NULL 時,沒有內容被填充,此時 addrlen不被使用,同時也可以是 NULL。
參數 addrlen 是一個“值-返回”型參數,調用者必須把它初始化為 addr指向的結構的大小(字節數),返回時,它指出端地址的實際大小。
如果提供的緩沖區太小,返回的地址將被截斷,此時,addrlen 將返回一個比傳入更大的值。
如果隊列里沒有未處理的連接,并且套接口沒有標記為不阻塞,accept()會阻塞當前調用進程直到有一個連接出現。如果沒有未處理的連接,同時套接口被標記為不阻塞,accept() 返回EAGAIN 或 EWOULDBLOCK 錯誤。
為了在一個套接口有連接時收到通知,你可以使用 select(2) 或 poll(2)。當有連接時,一個可讀事件被遞送。進一步,你可以設置當一個套接口可用時,發送一個SIGIO,參看 socket(7)來詳細了解。
對于一些需要顯示驗證的協議,比如說 DECNet,accept()只是從隊列里取出連接請求,并沒有執行驗證。驗證將在下次對新建的文件描述符進行正常的讀或寫時進行,并且拒絕可以通過關閉那個新建的套接口來進行。目前在Linux 中只有 DECNet 有如此語義。
flags 是 0,那么 accept4() 與 accept() 功能一樣。下面flags 的值可能通過位求或運算來得到不同的行為:
- SOCK_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 一樣重試一次。對于 TCP/IP來說,這些錯誤有 ENETDOWN、 EPROTO、 ENOPROTOOPT、 EHOSTDOWN、 ENONET、 EHOSTUNREACH、 EOPNOTSUPP和 ENETUNREACH。錯誤
- EAGAIN 或 EWOULDBLOCK
- 套接口被標記為非阻塞并且沒有連接等待接受。POSIX.1-2001允許在此時返回這兩種錯誤,但沒有要求兩個常量必須具有相同的值,所以可移植的程序應該同時檢查兩者。 EBADF
- 描述符無效。 ECONNABORTED
- 一個連接已經中止了。 EFAULT
- 參數 addr 不在可寫的用戶地址空間里。 EINTR
- 在一個有效的連接到達之前,本系統調用被信號中斷,參看 signal(7)。 EINVAL
- 套接口不在監聽連接,或 addrlen 無效(如是負數)。 EINVAL
- (accept4()) 在 flags 中有無效的值。 EMFILE
- 達到單個進程打開的文件描述上限。 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)。accept4() 是非標準 Linux 擴展。
在 Linux 系統里,accept() 返回的新建的套接口 不會 繼承監聽套接口的諸如O_NONBLOCK 和 O_ASYNC 這樣的文件狀態。這個行為與正規的 BSD套接口實現不一致。可移植的程序不應該假設文件狀態是繼承或不繼承的,總是顯示地設置 accept()返回的套接口需要的標記位。
注意
POSIX.1-2001 不要求包含 <sys/types.h>,并且這個頭文件在 Linux中也不要求。然而一些歷史(BSD)實現要求這個頭文件,可移植的應用程序應該包含這個文件。在 SIGIO 遞送之后,在 select(2) 或 poll(2) 返回但連接卻因為一個異步網絡錯誤而刪除之后,或在其它線程調用accept() 之前,不需要總是等待。如果這些事發生了,調用將被阻塞到一個新連接到來,為了讓accept() 絕不阻塞,傳入的 sockfd 需要設置 O_NONBLOCK 標記(參看socket(7))。
socklen_t 類型
accept() 的第三個參數最初被聲明為 int* (在 libc4 和 libc5,以及一些諸如4.x BSD、SunOS4、SGI)。POSIX.1g 草案想把它改為 size_t *,這與SunOS 5是一樣的,接著 POSIX 草案提出了 socklen_t *,并且在 Single UnixSpecification 和 glibc2 也是如此。Linus Torvalds 曾說:“任何合理的庫都必須保證 socklen_t 與 int 有相同的長度。否則的話都會與 BSD 套接口不同。POSIX 最初把它定義 為 size_t ,而我(同時也希望其他人,但顯然不是太多)對他們表示強烈的不贊同。把它定義為 size_t將是完全地不兼容,尤其在 64 位系統里,size_t 很少跟 int 有相同的寬度。它 必須 與 int有相同的寬度,因為 BSD 接口是這樣的。無論如何,制定 POSIX 的人還是創造出 socklen_t了。他們最初不應該去碰這個東西,但是一旦他們碰了,變會因為一些深奧的原因提供一個命名的類型(可能有些人因為之前愚笨的行為而丟臉時,就會靜悄悄地他們的行為換個名字)。”
示例
參考 bind(2)。參看
bind(2), connect(2), listen(2), select(2), socket(2), socket(7)
英文原版:http://man7.org/linux/man-pages/dir_all_alphabetic.html
總結
以上是生活随笔為你收集整理的ACCEPT()和ACCEPT4()的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 在相遇的时候是什么歌呢?
- 下一篇: 保险柜多少钱一个,小的?
