【UNIX網絡編程(二)】基本TCP套接字編程函數

基於TCP客戶/server程序的套接字函數圖例如如下:網絡


運行網絡I/O。一個進程必須作的第一件事就是調用socket函數。指按期望的通訊協議類型。socket

#include <sys/socket.h>函數

int socket(int family, int type, int protocol);/*返回值:若成功則爲非負描寫敘述符,若出錯則爲-1*/spa

socket函數成功時返回一個小的非負整數值,它與文件描寫敘述符相似。把它稱爲套接字描寫敘述符,簡稱sockfd。family參數指明協議族。被稱爲協議域。type參數指明套接字類型。指針

protocol參數應該是某個協議類型常值。或者爲0,以選擇所給定family和type組合的系統默認值。server

各參數列於一下表格:接口

family 說明 type 說明 protocol 說明
AF_INET IPv4協議 SOCKET_STREAM 字節流套接字 IPPROTO_TCP TCP傳輸協議
AF_INET6
IPv6協議 SOCK_DGRAM 數據報套接字 IPPROTO_UDP UDP傳輸協議
AF_LOCAL Unix域協議 SOCK_SEQPACKET 有序分組套接字 IPPROTO_SCTP SCTP傳輸協議
AF_ROUTE 路由套接字 SOCK_RAM 原始套接字

AF_KEY 祕鑰套接字




TCP客戶用connect函數來創建與TCPserver的連接。生命週期

#include <sys/socket.h>隊列

int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen);  /*返回:若成功則爲0。若出錯則爲-1*/進程

sockfd是由socket函數返回的套接字描寫敘述符。第二個、第三個參數各自是一個指向套接字地址結構的指針和該結構的大小。客戶在調用函數connect前沒必要非得調用bind函數,因爲假設需要的話,內核會肯定源IP地址,並選擇一個暫時port號做爲源port。假設是TCP套接字,調用connect函數將激發TCP的三路握手過程,而且僅在鏈接創建成功或出錯時才返回,當中出錯返回可能有下面幾種狀況:

a、若TCP客戶沒有收到SYN分節的響應,則返回ETIMEDOUT錯誤。

b、若對客戶的SYN的響應是RST(表示復位),則代表該server主機在咱們指定的port上沒有進程在等待與之鏈接。

c、若客戶發出的SYN在中間的某個路由器上引起了一個「destination unreachable」ICMP錯誤。則以爲是一個軟錯誤。


bind函數把一個本地協議地址賦予一個套接字。對於網際網協議,協議地址是32位的IPv4地址與16位的TCP或UDPport號的組合。


#include <sys/socket.h>

int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);/*返回,成功則爲0,出錯則爲-1*/

第二個參數是一個指向特定於協議的地址結構的指針。第三個參數是該地址結構的長度,對於TCP。調用bind函數可以指定一個port號。或指定一個IP地址,也可以二者都指定。還可以都不指定。

server在啓動時捆綁它們的衆所周知port。假設一個TCP客戶或server不曾調用bind捆綁一個port,當調用connect或listen時。內核就要爲對應的套接字選擇一個暫時port號。讓內核選擇暫時port對於TCP客戶來講是正常的。除非應用需要一個預留port;而毀於TCPserver來講卻極爲罕見,因爲server是經過他們的衆所周知port被你們認識的。

進程可以把一個特定的IP地址捆綁到它的套接字上,只是這個IP地址必須屬於其所在主機的網絡接口之中的一個。

假設指定port號爲0,那麼內核就bind被調用時選擇一個暫時port。然而假設指定IP地址爲通配地址。那麼內核將等到套接字已鏈接TCP或已在套接字上發出數據報時才選擇一個IP地址。對於IPv4來講,通配地址由常量INADDR_ANY來指定,其值爲0。

注意:假設讓內核來爲套接字選擇一個暫時port號,那麼必須注意。函數bind並不返回所選擇的值。實際上。由於bind函數的第二個參數有const限定詞,它沒法返回所選之值。

爲了獲得內核所選擇的這個暫時port值,必須調用函數getsockanme來返回協議地址。


listen函數僅由TCPserver調用,它作兩件事:

一、當socket函數建立一個套接字時,它被若是爲一個主動套接字,也就是說。它是一個將調用connect發起鏈接的客戶套接字。listen函數把一個未鏈接的套接字轉換成一個被動套接字,指示內核應該受指向該套接字的鏈接請求。

二、本函數的第二個參數規定了內核應該爲對應套接字排隊的最大鏈接個數。

#include <sys/socket.h>

int listen(int sockfd, int backlog);/*返回:若成功則爲0。出錯則爲-1*/

本函數一般應該在調用socket和bind這兩個函數以後。並在調用accept函數以前調用。

爲理解backlog參數。必須認識到內核爲不論什麼一個給定的監聽套接字維護兩個隊列:

一、未完畢鏈接隊列。每個這種SYN分節相應當中一項:已由某個客戶發出併到達server,而server正在等待完畢相應的TCP三路握手過程,這些套接字處於SYN_RCVD狀態

二、已完畢鏈接隊列,每個已完畢TCP三路握手過程的客戶相應當中一項。這些套接字處於ESTBLISHED狀態。


accept函數由TCPserver調用,用於從已完畢鏈接隊列返回下一個已完畢鏈接。假設已完畢鏈接隊列爲空,那麼進程被投入睡眠。

#include <sys/socket.h>

int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);   /*返回:若成功則爲負描寫敘述符。若出錯則爲-1*/

參數cliaddr和addrlen用來返回已鏈接的對端進程協議地址。假設accept成功,那麼其返回值是由內核本身主動生成的一個全新描寫敘述符,表明與所返回客戶的TCP連接。在討論accept函數時,稱第一個參數爲監聽套接字描寫敘述符。稱返回值爲已鏈接套接字描寫敘述符。區分這兩個套接字很重要。

一個server一般只建立一個監聽套接字,它在該server的生命週期內一直存在。

內核爲每個由server進程接受的客戶鏈接建立一個已鏈接套接字。當server完畢對某個給定客戶的服務時,對應的一兩節套接字就被關閉。

本函數最多返回3個值:一個既多是新套接字描寫敘述符也多是出錯僅僅是的整數、客戶進程的協議地址以及該地址的大小。假設對返回客戶協議地址不感興趣,可以把cliaddr和addrlen均置爲空指針。


close函數用來關閉套接字。並終止TCP鏈接。int close(int sockfd)。返回:成功則爲0。出錯則爲-1。

相關文章
相關標籤/搜索