• 正文
  • 相關(guān)推薦
申請(qǐng)入駐 產(chǎn)業(yè)圖譜

套接字函數(shù) | socket、bind、listen、accept、connect

03/04 08:53
1554
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

socket模型創(chuàng)建流程圖

socket函數(shù)

#include?<sys/types.h>?/* See NOTES */#include?<sys/socket.h>int?socket(int?domain,?int?type,?int?protocol);

domain:

AF_INET 這是大多數(shù)用來產(chǎn)生socket的協(xié)議,使用TCPUDP來傳輸,用IPv4的地址。

AF_INET6 與上面類似,不過是來用IPv6的地址。

AF_UNIX 本地協(xié)議,使用在Unix和Linux系統(tǒng)上,一般都是當(dāng)客戶端和服務(wù)器在同一臺(tái)及其上的時(shí)候使用。

type:

SOCK_STREAM 這個(gè)協(xié)議是按照順序的、可靠的、數(shù)據(jù)完整的基于字節(jié)流的連接。這是一個(gè)使用最多的socket類型,這個(gè)socket是使用TCP來進(jìn)行傳輸。

SOCK_DGRAM 這個(gè)協(xié)議是無連接的、固定長度的傳輸調(diào)用。該協(xié)議是不可靠的,使用UDP來進(jìn)行它的連接。

SOCK_SEQPACKET該協(xié)議是雙線路的、可靠的連接,發(fā)送固定長度的數(shù)據(jù)包進(jìn)行傳輸。必須把這個(gè)包完整的接受才能進(jìn)行讀取。

SOCK_RAW socket類型提供單一的網(wǎng)絡(luò)訪問,這個(gè)socket類型使用ICMP公共協(xié)議。(ping、traceroute使用該協(xié)議)

SOCK_RDM 這個(gè)類型是很少使用的,在大部分的操作系統(tǒng)上沒有實(shí)現(xiàn),它是提供給數(shù)據(jù)鏈路層使用,不保證數(shù)據(jù)包的順序。

protocol:

傳0 表示使用默認(rèn)協(xié)議。

返回值:

成功:返回指向新創(chuàng)建的socket的文件描述符,失?。悍祷?1,設(shè)置errno。

socket()打開一個(gè)網(wǎng)絡(luò)通訊端口,如果成功的話,就像open()一樣返回一個(gè)文件描述符,應(yīng)用程序可以像讀寫文件一樣用read/write在網(wǎng)絡(luò)上收發(fā)數(shù)據(jù),如果socket()調(diào)用出錯(cuò)則返回-1。對(duì)于IPv4,domain參數(shù)指定為AF_INET。對(duì)于TCP協(xié)議,type參數(shù)指定為SOCK_STREAM,表示面向流的傳輸協(xié)議。如果是UDP協(xié)議,則type參數(shù)指定為SOCK_DGRAM,表示面向數(shù)據(jù)報(bào)的傳輸協(xié)議。protocol參數(shù)的介紹從略,指定為0即可。

bind函數(shù)

#include?<sys/types.h>?/* See NOTES */#include?<sys/socket.h>int?bind(int?sockfd,?const?struct?sockaddr *addr,?socklen_t?addrlen);

sockfd:

socket文件描述符。

addr:

構(gòu)造出IP地址加端口號(hào)。

addrlen:

sizeof(addr)長度。

返回值:

成功返回0,失敗返回-1, 設(shè)置errno。

服務(wù)器程序所監(jiān)聽的網(wǎng)絡(luò)地址和端口號(hào)通常是固定不變的,客戶端程序得知服務(wù)器程序的地址和端口號(hào)后就可以向服務(wù)器發(fā)起連接,因此服務(wù)器需要調(diào)用bind綁定一個(gè)固定的網(wǎng)絡(luò)地址和端口號(hào)。

bind()的作用是將參數(shù)sockfd和addr綁定在一起,使sockfd這個(gè)用于網(wǎng)絡(luò)通訊的文件描述符監(jiān)聽addr所描述的地址和端口號(hào)。前面講過,struct sockaddr *是一個(gè)通用指針類型,addr參數(shù)實(shí)際上可以接受多種協(xié)議的sockaddr結(jié)構(gòu)體,而它們的長度各不相同,所以需要第三個(gè)參數(shù)addrlen指定結(jié)構(gòu)體的長度。如:

struct?sockaddr_in servaddr;bzero(&servaddr,?sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(6666);

首先將整個(gè)結(jié)構(gòu)體清零,然后設(shè)置地址類型為AF_INET,網(wǎng)絡(luò)地址為INADDR_ANY,這個(gè)宏表示本地的任意IP地址,因?yàn)榉?wù)器可能有多個(gè)網(wǎng)卡,每個(gè)網(wǎng)卡也可能綁定多個(gè)IP地址,這樣設(shè)置可以在所有的IP地址上監(jiān)聽,直到與某個(gè)客戶端建立了連接時(shí)才確定下來到底用哪個(gè)IP地址,端口號(hào)為6666。

listen函數(shù)

#include?<sys/types.h>?/* See NOTES */#include?<sys/socket.h>int?listen(int?sockfd,?int?backlog);

sockfd:

socket文件描述符。

backlog:

排隊(duì)建立3次握手隊(duì)列和剛剛建立3次握手隊(duì)列的鏈接數(shù)和。

查看系統(tǒng)默認(rèn)backlog

cat?/proc/sys/net/ipv4/tcp_max_syn_backlog

典型的服務(wù)器程序可以同時(shí)服務(wù)于多個(gè)客戶端,當(dāng)有客戶端發(fā)起連接時(shí),服務(wù)器調(diào)用的accept()返回并接受這個(gè)連接,如果有大量的客戶端發(fā)起連接而服務(wù)器來不及處理,尚未accept的客戶端就處于連接等待狀態(tài),listen()聲明sockfd處于監(jiān)聽狀態(tài),并且最多允許有backlog個(gè)客戶端處于連接待狀態(tài),如果接收到更多的連接請(qǐng)求就忽略。listen()成功返回0,失敗返回-1。

accept函數(shù)

#include?<sys/types.h>? ? ?/* See NOTES */#include?<sys/socket.h>int?accept(int?sockfd,?struct?sockaddr *addr,?socklen_t?*addrlen);

sockdf:

socket文件描述符。

addr:

傳出參數(shù),返回鏈接客戶端地址信息,含IP地址和端口號(hào)。

addrlen:

傳入傳出參數(shù)(值-結(jié)果),傳入sizeof(addr)大小,函數(shù)返回時(shí)返回真正接收到地址結(jié)構(gòu)體的大小。

返回值:

成功返回一個(gè)新的socket文件描述符,用于和客戶端通信,失敗返回-1,設(shè)置errno

三方握手完成后,服務(wù)器調(diào)用accept()接受連接,如果服務(wù)器調(diào)用accept()時(shí)還沒有客戶端的連接請(qǐng)求,就阻塞等待直到有客戶端連接上來。addr是一個(gè)傳出參數(shù),accept()返回時(shí)傳出客戶端的地址和端口號(hào)。addrlen參數(shù)是一個(gè)傳入傳出參數(shù)(value-result argument),傳入的是調(diào)用者提供的緩沖區(qū)addr的長度以避免緩沖區(qū)溢出問題,傳出的是客戶端地址結(jié)構(gòu)體的實(shí)際長度(有可能沒有占滿調(diào)用者提供的緩沖區(qū))。如果給addr參數(shù)傳NULL,表示不關(guān)心客戶端的地址。

我們的服務(wù)器程序結(jié)構(gòu)是這樣的:

while?(1) {cliaddr_len = sizeof(cliaddr);connfd =?accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);n =?read(connfd, buf, MAXLINE);
......
close(connfd);
}

整個(gè)是一個(gè)while死循環(huán),每次循環(huán)處理一個(gè)客戶端連接。由于cliaddr_len是傳入傳出參數(shù),每次調(diào)用accept()之前應(yīng)該重新賦初值。accept()的參數(shù)listenfd是先前的監(jiān)聽文件描述符,而accept()的返回值是另外一個(gè)文件描述符connfd,之后與客戶端之間就通過這個(gè)connfd通訊,最后關(guān)閉connfd斷開連接,而不關(guān)閉listenfd,再次回到循環(huán)開頭listenfd仍然用作accept的參數(shù)。accept()成功返回一個(gè)文件描述符,出錯(cuò)返回-1。

connect函數(shù)

#include?<sys/types.h>? ? ? ? ? ?/* See NOTES */#include?<sys/socket.h>int?connect(int?sockfd,?const?struct?sockaddr *addr,?socklen_t?addrlen);

sockdf:

socket文件描述符。

addr:

傳入?yún)?shù),指定服務(wù)器端地址信息,含IP地址和端口號(hào)。

addrlen:

傳入?yún)?shù),傳入sizeof(addr)大小。

返回值:

成功返回0,失敗返回-1,設(shè)置errno。

客戶端需要調(diào)用connect()連接服務(wù)器,connect和bind的參數(shù)形式一致,區(qū)別在于bind的參數(shù)是自己的地址,而connect的參數(shù)是對(duì)方的地址。connect()成功返回0,出錯(cuò)返回-1。

相關(guān)推薦

登錄即可解鎖
  • 海量技術(shù)文章
  • 設(shè)計(jì)資源下載
  • 產(chǎn)業(yè)鏈客戶資源
  • 寫文章/發(fā)需求
立即登錄

Linux、C、C++、Python、Matlab,機(jī)器人運(yùn)動(dòng)控制、多機(jī)器人協(xié)作,智能優(yōu)化算法,貝葉斯濾波與卡爾曼濾波估計(jì)、多傳感器信息融合,機(jī)器學(xué)習(xí),人工智能。