socket程式設計之accept()函式
名稱
accept()
接收一個套接字中已建立的連線
使用格式
#include <sys/socket.h>
int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen);
功能引數描述
accept()系統呼叫主要用在基於連線的套接字型別,比如SOCK_STREAM和SOCK_SEQPACKET。它提取出所監聽套接字的等待連線佇列中第一個連線請求,建立一個新的套接字,並返回指向該套接字的檔案描述符。新建立的套接字不在監聽狀態,原來所監聽的套接字也不受該系統呼叫的影響。
備註:新建立的套接字準備傳送send()和接收資料recv()。
引數:
sockfd, 利用系統呼叫socket()建立的套接字描述符,通過bind()繫結到一個本地地址(一般為伺服器的套接字),並且通過listen()一直在監聽連線;
addr, 指向struct sockaddr的指標,該結構用通訊層伺服器對等套接字的地址(一般為客戶端地址)填寫,返回地址addr的確切格式由套接字的地址類別(比如TCP或UDP)決定;若addr為NULL,沒有有效地址填寫,這種情況下,addrlen也不使用,應該置為NULL;
備註:addr是個指向區域性資料結構sockaddr_in的指標,這就是要求接入的資訊本地的套接字(地址和指標)。
addrlen
備註:addrlen是個區域性整形變數,設定為sizeof(struct sockaddr_in)。
如果佇列中沒有等待的連線,套接字也沒有被標記為Non-blocking,accept()會阻塞呼叫函式直到連接出現;如果套接字被標記為Non-blocking,佇列中也沒有等待的連線,accept()返回錯誤EAGAIN或EWOULDBLOCK。
備註:一般來說,實現時accept()為阻塞函式,當監聽socket呼叫accept()時,它先到自己的receive_buf中檢視是否有連線資料包;
若有,把資料拷貝出來,刪掉接收到的資料包,建立新的socket與客戶發來的地址建立連線;
若沒有,就阻塞等待;
為了在套接字中有到來的連線時得到通知,可以使用select()或poll()。當嘗試建立新連線時,系統傳送一個可讀事件,然後呼叫accept()為該連接獲取套接字。另一種方法是,當套接字中有連線到來時設定套接字傳送SIGIO訊號。
返回值
成功時,返回非負整數,該整數是接收到套接字的描述符;出錯時,返回-1,相應地設定全域性變數errno。
錯誤處理
Linux下,accept()把已等待的網路錯誤傳給新建立的連線,當作是accept()返回的錯誤。這於其他的BSD實現是不同的。為了可靠執行,應該在accept()之後檢測協議已定義的一些網路錯誤,並把這些錯誤當作EAGAIN並重試。對於TCP/IP協議來說,主要有錯誤:ENETDOWN,EPROTO,ENOPROTOOPT,EHOSTDOWN,ENONET,EHOSTUNREACH,EOPNOTSUPP和ENETUNREACH。