【UNIX网络编程(二)】基本TCP套接字编程函数
基于TCP客戶/server程序的套接字函數(shù)圖例如以下:
運行網(wǎng)絡I/O。一個進程必須做的第一件事就是調(diào)用socket函數(shù)。指定期望的通信協(xié)議類型。
#include <sys/socket.h>
int socket(int family, int type, int protocol);/*返回值:若成功則為非負描寫敘述符,若出錯則為-1*/
socket函數(shù)成功時返回一個小的非負整數(shù)值,它與文件描寫敘述符類似。把它稱為套接字描寫敘述符,簡稱sockfd。family參數(shù)指明協(xié)議族。被稱為協(xié)議域。type參數(shù)指明套接字類型。
protocol參數(shù)應該是某個協(xié)議類型常值。或者為0,以選擇所給定family和type組合的系統(tǒng)默認值。
各參數(shù)列于一下表格:
| family | 說明 | type | 說明 | protocol | 說明 |
| AF_INET | IPv4協(xié)議 | SOCKET_STREAM | 字節(jié)流套接字 | IPPROTO_TCP | TCP傳輸協(xié)議 |
| AF_INET6 | IPv6協(xié)議 | SOCK_DGRAM | 數(shù)據(jù)報套接字 | IPPROTO_UDP | UDP傳輸協(xié)議 |
| AF_LOCAL | Unix域協(xié)議 | SOCK_SEQPACKET | 有序分組套接字 | IPPROTO_SCTP | SCTP傳輸協(xié)議 |
| AF_ROUTE | 路由套接字 | SOCK_RAM | 原始套接字 | ||
| AF_KEY | 秘鑰套接字 |
TCP客戶用connect函數(shù)來建立與TCPserver的鏈接。
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen); ?/*返回:若成功則為0。若出錯則為-1*/
sockfd是由socket函數(shù)返回的套接字描寫敘述符。第二個、第三個參數(shù)各自是一個指向套接字地址結(jié)構(gòu)的指針和該結(jié)構(gòu)的大小。客戶在調(diào)用函數(shù)connect前不必非得調(diào)用bind函數(shù),由于假設須要的話,內(nèi)核會確定源IP地址,并選擇一個暫時port號作為源port。假設是TCP套接字,調(diào)用connect函數(shù)將激發(fā)TCP的三路握手過程,并且僅在連接建立成功或出錯時才返回,當中出錯返回可能有下面幾種情況:
a、若TCP客戶沒有收到SYN分節(jié)的響應,則返回ETIMEDOUT錯誤。
b、若對客戶的SYN的響應是RST(表示復位),則表明該server主機在我們指定的port上沒有進程在等待與之連接。
c、若客戶發(fā)出的SYN在中間的某個路由器上引發(fā)了一個“destination unreachable”ICMP錯誤。則覺得是一個軟錯誤。
bind函數(shù)把一個本地協(xié)議地址賦予一個套接字。對于網(wǎng)際網(wǎng)協(xié)議,協(xié)議地址是32位的IPv4地址與16位的TCP或UDPport號的組合。
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);/*返回,成功則為0,出錯則為-1*/
第二個參數(shù)是一個指向特定于協(xié)議的地址結(jié)構(gòu)的指針。第三個參數(shù)是該地址結(jié)構(gòu)的長度,對于TCP。調(diào)用bind函數(shù)能夠指定一個port號。或指定一個IP地址,也能夠兩者都指定。還能夠都不指定。
server在啟動時捆綁它們的眾所周知port。假設一個TCP客戶或server未曾調(diào)用bind捆綁一個port,當調(diào)用connect或listen時。內(nèi)核就要為對應的套接字選擇一個暫時port號。讓內(nèi)核選擇暫時port對于TCP客戶來說是正常的。除非應用須要一個預留port;而毀于TCPserver來說卻極為罕見,由于server是通過他們的眾所周知port被大家認識的。
進程能夠把一個特定的IP地址捆綁到它的套接字上,只是這個IP地址必須屬于其所在主機的網(wǎng)絡接口之中的一個。
假設指定port號為0,那么內(nèi)核就bind被調(diào)用時選擇一個暫時port。然而假設指定IP地址為通配地址。那么內(nèi)核將等到套接字已連接TCP或已在套接字上發(fā)出數(shù)據(jù)報時才選擇一個IP地址。對于IPv4來說,通配地址由常量INADDR_ANY來指定,其值為0。
注意:假設讓內(nèi)核來為套接字選擇一個暫時port號,那么必須注意。函數(shù)bind并不返回所選擇的值。實際上。因為bind函數(shù)的第二個參數(shù)有const限定詞,它無法返回所選之值。
為了得到內(nèi)核所選擇的這個暫時port值,必須調(diào)用函數(shù)getsockanme來返回協(xié)議地址。
listen函數(shù)僅由TCPserver調(diào)用,它做兩件事:
1、當socket函數(shù)創(chuàng)建一個套接字時,它被如果為一個主動套接字,也就是說。它是一個將調(diào)用connect發(fā)起連接的客戶套接字。listen函數(shù)把一個未連接的套接字轉(zhuǎn)換成一個被動套接字,指示內(nèi)核應該受指向該套接字的連接請求。
2、本函數(shù)的第二個參數(shù)規(guī)定了內(nèi)核應該為對應套接字排隊的最大連接個數(shù)。
#include <sys/socket.h>
int listen(int sockfd, int backlog);/*返回:若成功則為0。出錯則為-1*/
本函數(shù)通常應該在調(diào)用socket和bind這兩個函數(shù)之后。并在調(diào)用accept函數(shù)之前調(diào)用。
為理解backlog參數(shù)。必須認識到內(nèi)核為不論什么一個給定的監(jiān)聽套接字維護兩個隊列:
1、未完畢連接隊列。每一個這種SYN分節(jié)相應當中一項:已由某個客戶發(fā)出并到達server,而server正在等待完畢相應的TCP三路握手過程,這些套接字處于SYN_RCVD狀態(tài)
2、已完畢連接隊列,每一個已完畢TCP三路握手過程的客戶相應當中一項。這些套接字處于ESTBLISHED狀態(tài)。
accept函數(shù)由TCPserver調(diào)用,用于從已完畢連接隊列返回下一個已完畢連接。假設已完畢連接隊列為空,那么進程被投入睡眠。
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen); ? /*返回:若成功則為負描寫敘述符。若出錯則為-1*/
參數(shù)cliaddr和addrlen用來返回已連接的對端進程協(xié)議地址。假設accept成功,那么其返回值是由內(nèi)核自己主動生成的一個全新描寫敘述符,代表與所返回客戶的TCP鏈接。在討論accept函數(shù)時,稱第一個參數(shù)為監(jiān)聽套接字描寫敘述符。稱返回值為已連接套接字描寫敘述符。區(qū)分這兩個套接字很重要。
一個server通常只創(chuàng)建一個監(jiān)聽套接字,它在該server的生命周期內(nèi)一直存在。
內(nèi)核為每一個由server進程接受的客戶連接創(chuàng)建一個已連接套接字。當server完畢對某個給定客戶的服務時,對應的一兩節(jié)套接字就被關(guān)閉。
本函數(shù)最多返回3個值:一個既可能是新套接字描寫敘述符也可能是出錯僅僅是的整數(shù)、客戶進程的協(xié)議地址以及該地址的大小。假設對返回客戶協(xié)議地址不感興趣,能夠把cliaddr和addrlen均置為空指針。
close函數(shù)用來關(guān)閉套接字。并終止TCP連接。int close(int sockfd)。返回:成功則為0。出錯則為-1。
轉(zhuǎn)載于:https://www.cnblogs.com/mfrbuaa/p/5225231.html
總結(jié)
以上是生活随笔為你收集整理的【UNIX网络编程(二)】基本TCP套接字编程函数的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 22.网络提速(最短路)
- 下一篇: JConsole监控远程Tomcat服务