accept函数_基础套接字函数入门1
想不想自己寫(xiě)一個(gè)簡(jiǎn)單的QQ?想不想自己寫(xiě)一個(gè)聊天室?想不想知道2000年的人是如何上網(wǎng)的?本節(jié)講解一些基礎(chǔ)的網(wǎng)絡(luò)函數(shù),帶你看看,編寫(xiě)一個(gè)完整的TCP客戶端、服務(wù)端需要掌握哪些函數(shù)?之后,我們要開(kāi)發(fā)自己的QQ。
1 socket函數(shù)
// sys/socket.h /* 使用協(xié)議__protocol在域__domain中創(chuàng)建一個(gè)__type類型的新套接字。 如果__protocol為零,則自動(dòng)選擇一個(gè)。 返回新套接字的文件描述符,或者返回-1表示錯(cuò)誤。 */ extern int socket (int __domain, int __type, int __protocol) __THROW;- __domain:即family,AF_INETIPv4協(xié)議,AF_INET6IPv6協(xié)議
- __type:SOCK_STREAM字節(jié)流套接字,SOCK_DGRAM數(shù)據(jù)報(bào)套接字,SOCK_RAW原始套接字
- __protocol:IPPROTO_TCPTCP傳輸協(xié)議,IPPROTO_UDPUDP傳輸協(xié)議
socket函數(shù)在成功時(shí)返回一個(gè)小的非負(fù)整數(shù)值,它與文件描述符類似,我們把它稱為套接字描述符(socket descriptor),簡(jiǎn)稱socketfd。
AF_前綴表示地址族,PF_前綴表示協(xié)議族 ,因?yàn)闅v史上曾想讓一個(gè)協(xié)議族(PF)支持多個(gè)地址族(AF),用PF來(lái)創(chuàng)建套接字,用AF來(lái)創(chuàng)建套接字地址結(jié)構(gòu),然而就只是想想,沒(méi)有實(shí)現(xiàn)?,F(xiàn)在AF和PF的值是相等的。
// bits/socket.h /* Protocol families. */ #define PF_INET 2 /* IP protocol family. */ #define PF_INET6 10 /* IP version 6. */ /* Address families. */ #define AF_INET PF_INET #define AF_INET6 PF_INET62 connect函數(shù)
// sys/socket.h #define __CONST_SOCKADDR_ARG const struct sockaddr * extern int connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len);- __fd:socket函數(shù)返回的套接字描述符
- __addr:指向套接字結(jié)構(gòu)地址的指針
- __len:該套接字的大小
TCP客戶用connect函數(shù)和TCP服務(wù)器建立連接。客戶在調(diào)用connect函數(shù)前可以不調(diào)用bind函數(shù),因?yàn)槿绻行枰?#xff0c;內(nèi)核會(huì)確定本機(jī)IP地址,并選擇一個(gè)臨時(shí)端口作為源端口。
3 bind函數(shù)
// sys/socket.h /* 把一個(gè)本地協(xié)議地址賦值給一個(gè)套接字 */ #define __CONST_SOCKADDR_ARG const struct sockaddr * extern int bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len) __THROW;- 對(duì)于IPv4來(lái)說(shuō),協(xié)議地址是32位的IPv4地址和16位的端口號(hào)組合。
- 對(duì)于IPv6來(lái)說(shuō),協(xié)議地址是128位的IPv6地址和16位的端口號(hào)組合。
綁定操作涉及3個(gè)對(duì)象:套接字,地址和端口。其中套接字是捆綁的主體,地址和端口是捆綁的客體。在套接字上綁定地址和端口表示:該地址和端口已經(jīng)被套接字使用。
- 如果指定端口號(hào)為0,那么內(nèi)核在bind被調(diào)用的時(shí)候選擇一個(gè)臨時(shí)端口。
- 如果指定IP地址是通配地址,那么內(nèi)核將等到套接字已連接(TCP)或在套接字上發(fā)出數(shù)據(jù)報(bào)(UDP)時(shí)才選擇一個(gè)本地IP地址。
對(duì)于IPv4來(lái)說(shuō),通配地址是0(INADDR_ANY),如果讓內(nèi)核幫套接字選擇一個(gè)端口,那么必須注意,bind函數(shù)并不返回所選擇的端口號(hào)。因?yàn)閎ind函數(shù)的_addr參數(shù)有const限定詞,它無(wú)法返回所選的值。為了拿到內(nèi)核選擇的臨時(shí)端口,必須調(diào)用getsockname函數(shù)來(lái)返回協(xié)議地址。
4 listen函數(shù)
// sys/socket.h extern int listen (int __fd, int __n) __THROW;listen函數(shù)僅有TCP服務(wù)器調(diào)用,它做兩件事:
- 未完成連接隊(duì)列:每個(gè)處于三次握手中的TCP連接,套接字處于SYN_RCVD狀態(tài)。
- 已完成連接隊(duì)列:每個(gè)已完成三次握手的TCP連接,套接字處于ESTABLISHED狀態(tài)。
這2個(gè)隊(duì)列之和不能超過(guò)__n,否則就無(wú)法新建TCP連接,這就是SYN Flood攻擊的原理。
5 accept函數(shù)
// sys/socket.h extern int accept (int __fd, __SOCKADDR_ARG __addr,socklen_t *__restrict __addr_len);accept函數(shù)由TCP服務(wù)器調(diào)用,用于從已完成連接隊(duì)列的隊(duì)頭返回下一個(gè)已完成連接。如果該隊(duì)列為空,那么進(jìn)程被投入睡眠。(默認(rèn)套接字為阻塞方式)
參數(shù)__addr和__addr_len返回已連接的對(duì)端進(jìn)程的協(xié)議地址,即返回客戶端的協(xié)議地址。__addr_len是值-結(jié)果參數(shù),返回內(nèi)核存放在協(xié)議地址中實(shí)際的字節(jié)數(shù)。如果對(duì)客戶端的協(xié)議地址不感興趣,可以將指針置為NULL。
注意:如果accept成功,返回值是又內(nèi)核自動(dòng)生成的全新描述符,稱為已連接套接字。服務(wù)端與客戶通信,將用這個(gè)套接字,服務(wù)完成后,這個(gè)套接字就被關(guān)閉。 而參數(shù)__fd稱為監(jiān)聽(tīng)套接字, 一個(gè)服務(wù)僅僅創(chuàng)建一個(gè)監(jiān)聽(tīng)套接字。6 close函數(shù)
// /usr/include/unistd.h extern int close (int __fd);close函數(shù)一般可以用來(lái)關(guān)閉套接字,并終止TCP連接。但是在并發(fā)服務(wù)器中,close函數(shù)僅僅將套接字描述符引用計(jì)數(shù)減1。所以并不能一定在TCP連接上發(fā)送FIN報(bào)文,如果想在TCP連接上發(fā)送FIN報(bào)文,可以用shutdown函數(shù)。
參考文獻(xiàn):《UNIX網(wǎng)絡(luò)編程 卷1:套接字聯(lián)網(wǎng)API》
總結(jié)
以上是生活随笔為你收集整理的accept函数_基础套接字函数入门1的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: python pypdf2另存为图片_用
- 下一篇: excel 复制数据 sql serve