linux中socket的理解---4
一、socket
一般來說socket有一個(gè)別名也叫做套接字。
socket起源于Unix,都可以用“打 開open –> 讀寫write/read –> 關(guān)閉close”模式來操作。Socket就是該模式的一個(gè)實(shí)現(xiàn),socket即是一種特殊的文件,一些socket函數(shù)就是對(duì)其進(jìn)行的操作(讀/寫 IO、打開、關(guān)閉)。
說白了Socket是應(yīng)用層與TCP/IP 協(xié)議族通信的中間軟件抽象層,它是一組接口。在設(shè)計(jì)模式中,Socket其實(shí)就是一個(gè)門面模式,它把復(fù)雜的TCP/IP協(xié)議族隱藏在Socket接口后 面,對(duì)用戶來說,一組簡(jiǎn)單的接口就是全部,讓Socket去組織數(shù)據(jù),以符合指定的協(xié)議,而不需要讓用戶自己去定義什么時(shí)候需要指定哪個(gè)協(xié)議哪個(gè)函數(shù)。
? ? 其實(shí)socket也沒有層的概念,它只是一個(gè)facade設(shè)計(jì)模式的應(yīng)用,讓編程變的更簡(jiǎn)單。是一個(gè)軟件抽象層。在網(wǎng)絡(luò)編程中,我們大量用的都是通過socket實(shí)現(xiàn)的。
1.1套接字描述符
其實(shí)就是一個(gè)整數(shù),我們最熟悉的句柄是0、1、2三個(gè),0是標(biāo)準(zhǔn)輸入,1是標(biāo)準(zhǔn)輸出,2是標(biāo)準(zhǔn)錯(cuò)誤輸出。0、1、2是整數(shù)表示的,對(duì)應(yīng)的FILE *結(jié)構(gòu)的表示就是stdin、stdout、stderr
套接字API最初是作為UNIX操作系統(tǒng)的一部分而開發(fā)的,所以套接字API 與系統(tǒng)的其他I/O設(shè)備集成在一起。特別是,當(dāng)應(yīng)用程序要為因特網(wǎng)通信而創(chuàng)建一個(gè)套接字(socket)時(shí),操作系統(tǒng)就返回一個(gè)小整數(shù)作為描述符 (descriptor)來標(biāo)識(shí)這個(gè)套接字。然后,應(yīng)用程序以該描述符作為傳遞參數(shù),通過調(diào)用函數(shù)來完成某種操作(例如通過網(wǎng)絡(luò)傳送數(shù)據(jù)或接收輸入的數(shù) 據(jù))。
在許多操作系統(tǒng)中,套接字描述符和其他I/O描述符是集成在一起的,所以應(yīng)用程序可以對(duì)文件進(jìn)行套接字I/O或I/O讀/寫操作。
當(dāng)應(yīng)用程序要?jiǎng)?chuàng)建一個(gè)套接字時(shí),操作系統(tǒng)就返回一個(gè)小整數(shù)作為描述符,應(yīng)用程 序則使用這個(gè)描述符來引用該套接字需要I/O請(qǐng)求的應(yīng)用程序請(qǐng)求操作系統(tǒng)打開一個(gè)文件。操作系統(tǒng)就創(chuàng)建一個(gè)文件描述符提供給應(yīng)用程序訪問文件。從應(yīng)用程序 的角度看,文件描述符是一個(gè)整數(shù),應(yīng)用程序可以用它來讀寫文件。下圖顯示,操作系統(tǒng)如何把文件描述符實(shí)現(xiàn)為一個(gè)指針數(shù)組,這些指針指向內(nèi)部數(shù)據(jù)結(jié)構(gòu)。
?對(duì)于每個(gè)程序系統(tǒng)都有一張單獨(dú)的表。精確地講,系統(tǒng)為每個(gè)運(yùn)行的進(jìn)程維護(hù)一張單 獨(dú)的文件描述符表。當(dāng)進(jìn)程打開一個(gè)文件時(shí),系統(tǒng)把一個(gè)指向此文件內(nèi)部數(shù)據(jù)結(jié)構(gòu)的指針寫入文件描述符表,并把該表的索引值返回給調(diào)用者?。應(yīng)用程序只需記住 這個(gè)描述符,并在以后操作該文件時(shí)使用它。操作系統(tǒng)把該描述符作為索引訪問進(jìn)程描述符表,通過指針找到保存該文件所有的信息的數(shù)據(jù)結(jié)構(gòu)。
針對(duì)套接字的系統(tǒng)數(shù)據(jù)結(jié)構(gòu):
? ?1)、套接字API里有個(gè)函數(shù)socket,它就是用來創(chuàng)建一個(gè)套接字。套接字設(shè)計(jì)的總體思路是,單個(gè)系統(tǒng)調(diào)用就可以創(chuàng)建任何套接字,因?yàn)樘捉幼质窍喈?dāng) 籠統(tǒng)的。一旦套接字創(chuàng)建后,應(yīng)用程序還需要調(diào)用其他函數(shù)來指定具體細(xì)節(jié)。例如調(diào)用socket將創(chuàng)建一個(gè)新的描述符條目:
? ?2)、雖然套接字的內(nèi)部數(shù)據(jù)結(jié)構(gòu)包含很多字段,但是系統(tǒng)創(chuàng)建套接字后,大多數(shù)字字段沒有填寫。應(yīng)用程序創(chuàng)建套接字后在該套接字可以使用之前,必須調(diào)用其他的過程來填充這些字段。
二、基本的socket接口函數(shù)
?
服務(wù)器端先初始化/創(chuàng)建Socket,然后與端口綁定/綁定地址 (bind),對(duì)端口進(jìn)行監(jiān)聽(listen),調(diào)用accept阻塞/等待連續(xù),等待客戶端連接。在這時(shí)如果有個(gè)客戶端初始化一個(gè)Socket,然后連 接服務(wù)器(connect),如果連接成功,這時(shí)客戶端與服務(wù)器端的連接就建立了。客戶端發(fā)送數(shù)據(jù)請(qǐng)求,服務(wù)器端接收請(qǐng)求并處理請(qǐng)求,然后把回應(yīng)數(shù)據(jù)發(fā)送 給客戶端,客戶端讀取數(shù)據(jù),最后關(guān)閉連接,一次交互結(jié)束。
2.1socket函數(shù)
函數(shù)原型
int socket(int protofamily, int type, int protocol);?
?
返回值:
//返回sockfd ? ??sockfd是描述符,類似于open函數(shù)。
函數(shù)功能:
socket函數(shù)對(duì)應(yīng)于普通文件的打開操作。普通文件的打開操作返回一個(gè)文件 描述字,而socket()用于創(chuàng)建一個(gè)socket描述符(socket descriptor),它唯一標(biāo)識(shí)一個(gè)socket。這個(gè)socket描述字跟文件描述字一樣,后續(xù)的操作都有用到它,把它作為參數(shù),通過它來進(jìn)行一些 讀寫操作。
函數(shù)參數(shù):
protofamily:即協(xié)議域,又稱為協(xié)議族(family)。常用的協(xié) 議族有,AF_INET(IPV4)、AF_INET6(IPV6)、AF_LOCAL(或稱AF_UNIX,Unix域socket)、 AF_ROUTE等等。協(xié)議族決定了socket的地址類型,在通信中必須采用對(duì)應(yīng)的地址,如AF_INET決定了要用ipv4地址(32位的)與端口號(hào) (16位的)的組合、AF_UNIX決定了要用一個(gè)絕對(duì)路徑名作為地址。
? ? ?
type:指定socket類型。常用的socket類型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等。
? ? ?
protocol:就是指定協(xié)議。常用的協(xié)議有,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,它們分別對(duì)應(yīng)TCP傳輸協(xié)議、UDP傳輸協(xié)議、STCP傳輸協(xié)議、TIPC傳輸協(xié)議
注意:并不是上面的type和protocol可以隨意組合的,如SOCK_STREAM不可以跟IPPROTO_UDP組合。當(dāng)protocol為0時(shí),會(huì)自動(dòng)選擇type類型對(duì)應(yīng)的默認(rèn)協(xié)議。
當(dāng)我們調(diào)用socket創(chuàng)建一個(gè)socket時(shí),返回的socket描述字它存在 于協(xié)議族(address family,AF_XXX)空間中,但沒有一個(gè)具體的地址。如果想要給它賦值一個(gè)地址,就必須調(diào)用bind()函數(shù),否則就當(dāng)調(diào)用connect()、 listen()時(shí)系統(tǒng)會(huì)自動(dòng)隨機(jī)分配一個(gè)端口
2.2bind()函數(shù)
函數(shù)功能:
bind()函數(shù)把一個(gè)地址族中的特定地址賦給socket,也可以說是綁定ip端口和socket。例如對(duì)應(yīng)AF_INET、AF_INET6就是把一個(gè)ipv4或ipv6地址和端口號(hào)組合賦給socket。
函數(shù)原型:
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);函數(shù)參數(shù):
1.函數(shù)的三個(gè)參數(shù)分別為:sockfd:即socket描述字,它是通過socket()函數(shù)創(chuàng)建了,唯一標(biāo)識(shí)一個(gè)socket。bind()函數(shù)就是將給這個(gè)描述字綁定一個(gè)名字。
2.addr:一個(gè)const?struct?sockaddr *指針,指向要綁定給sockfd的協(xié)議地址。這個(gè)地址結(jié)構(gòu)根據(jù)地址創(chuàng)建socket時(shí)的地址協(xié)議族的不同而不同,
3.addrlen:對(duì)應(yīng)的是地址的長(zhǎng)度。
通用函數(shù)類型:
struct sockaddr{sa_family_t sa_family;char sa_data[14]; }如ipv4對(duì)應(yīng)的是:
struct sockaddr_in {sa_family_t sin_family; /* address family: AF_INET */in_port_t sin_port; /* port in network byte order 2字節(jié)*/struct in_addr sin_addr; /* internet address 4字節(jié)*/unsigned char sin_zero[8]; }; /* Internet address. */ struct in_addr {uint32_t s_addr; /* address in network byte order */ };ipv6對(duì)應(yīng)的是:?
Unix域?qū)?yīng)的是:?
通常服務(wù)器在啟動(dòng)的時(shí)候都會(huì)綁定一個(gè)眾所周知的地址(如ip地址+端口號(hào)),用于提供服務(wù),客戶就可以通過它來接連服務(wù)器;而客戶端就不用指定,有系統(tǒng)自動(dòng)分配一個(gè)端口號(hào)和自身的ip地址組合。這就是為什么通常服務(wù)器端在listen之前會(huì)調(diào)用bind(),而客戶端就不會(huì)調(diào)用,而是在connect()時(shí)由系統(tǒng)隨機(jī)生成一個(gè)。
2.2.1地址轉(zhuǎn)換
int_addr_t indet_addr(const char *cp)功能:將字符串形式的IP地址轉(zhuǎn)化為整數(shù)型的IP地址(網(wǎng)絡(luò)字節(jié)序)
? 范例:int_addr.saddr=inet_addr("192.168.1.1");
char *inet_ntoa(struct in_addr)? 功能:將整數(shù)形式的IP地址轉(zhuǎn)化為字符串形式的IP地址
2.2.2網(wǎng)絡(luò)字節(jié)序
網(wǎng)絡(luò)字節(jié)序定義:收到的第一個(gè)字節(jié)被當(dāng)作高位看待,這就要求發(fā)送端發(fā)送的第一個(gè)字節(jié)應(yīng)當(dāng)是高位。而在發(fā)送端發(fā)送數(shù)據(jù)時(shí),發(fā)送的第一個(gè)字節(jié)是該數(shù)字在內(nèi)存中起始地址對(duì)應(yīng)的字節(jié)。可見多字節(jié)數(shù)值在發(fā)送前,在內(nèi)存中數(shù)值應(yīng)該以大端法存放。?
網(wǎng)絡(luò)字節(jié)序說是大端字節(jié)序。
小端法(Little-Endian)就是低位字節(jié)排放在內(nèi)存的低地址端即該值的起始地址,高位字節(jié)排放在內(nèi)存的高地址端。?
大端法(Big-Endian)就是高位字節(jié)排放在內(nèi)存的低地址端即該值的起始地址,低位字節(jié)排放在內(nèi)存的高地址端。
網(wǎng)絡(luò)字節(jié)序轉(zhuǎn)化:---->不論是數(shù)據(jù)還是地址只要大于兩個(gè)字節(jié)就必須轉(zhuǎn)換
uint32_t htonl(uint32_t hostlong);將32位的數(shù)據(jù)從主機(jī)字節(jié)序轉(zhuǎn)換為網(wǎng)絡(luò)字節(jié)序in_addr.saddr = htonl(INADDR_ANY)uint16_t htons(uint16_t hostshort);將16位的數(shù)據(jù)從主機(jī)字節(jié)序轉(zhuǎn)換為網(wǎng)絡(luò)字節(jié)序uint32_t ntohl(uint32_t netlong);將32位的數(shù)據(jù)從網(wǎng)絡(luò)字節(jié)序轉(zhuǎn)換為主機(jī)字節(jié)序uint16_t ntohs(uint16_t netshort);將16位的數(shù)據(jù)從網(wǎng)絡(luò)字節(jié)序轉(zhuǎn)換為主機(jī)字節(jié)序2.3、listen()、connect()函數(shù)
如果作為一個(gè)服務(wù)器,在調(diào)用socket()、bind()之后就會(huì)調(diào)用listen()來監(jiān)聽這個(gè)socket,如果客戶端這時(shí)調(diào)用connect()發(fā)出連接請(qǐng)求,服務(wù)器端就會(huì)接收到這個(gè)請(qǐng)求。
int listen(int sockfd, int backlog);int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)listen函數(shù)的第一個(gè)參數(shù)即為要監(jiān)聽的socket描述字,第二個(gè)參數(shù)為相應(yīng)socket可以排隊(duì)的最大連接個(gè)數(shù)。socket()函數(shù)創(chuàng)建的socket默認(rèn)是一個(gè)主動(dòng)類型的,listen函數(shù)將socket變?yōu)楸粍?dòng)類型的,等待客戶的連接請(qǐng)求。
connect函數(shù)的第一個(gè)參數(shù)即為客戶端的socket描述字,第二參數(shù)為服務(wù)器的socket地址,第三個(gè)參數(shù)為socket地址的長(zhǎng)度。客戶端通過調(diào)用connect函數(shù)來建立與TCP服務(wù)器的連接。成功返回0,若連接失敗則返回-1。
2.4、accept()函數(shù)
TCP服務(wù)器端依次調(diào)用socket()、bind()、listen()之后,就會(huì)監(jiān)聽指定的socket地址了。TCP客戶端依次調(diào)用socket()、connect()之后就向TCP服務(wù)器發(fā)送了一個(gè)連接請(qǐng)求。TCP服務(wù)器監(jiān)聽到這個(gè)請(qǐng)求之后,就會(huì)調(diào)用accept()函數(shù)取接收請(qǐng)求,這樣連接就建立好了。之后就可以開始網(wǎng)絡(luò)I/O操作了,即類同于普通文件的讀寫I/O操作。
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); //返回連接connect_fd參數(shù)sockfd
參數(shù)sockfd就是上面解釋中的監(jiān)聽套接字,這個(gè)套接字用來監(jiān)聽一個(gè)端口,當(dāng)有一個(gè)客戶與服務(wù)器連接時(shí),它使用這個(gè)一個(gè)端口號(hào),而此時(shí)這個(gè)端口號(hào)正與這個(gè)套接字關(guān)聯(lián)。當(dāng)然客戶不知道套接字這些細(xì)節(jié),它只知道一個(gè)地址和一個(gè)端口號(hào)。參數(shù)addr 這是一個(gè)結(jié)果參數(shù),它用來接受一個(gè)返回值,這返回值指定客戶端的地址,當(dāng)然這個(gè)地址是通過某個(gè)地址結(jié)構(gòu)來描述的,用戶應(yīng)該知道這一個(gè)什么樣的地址結(jié)構(gòu)。如果對(duì)客戶的地址不感興趣,那么可以把這個(gè)值設(shè)置為NULL。參數(shù)len如果accept成功返回,則服務(wù)器與客戶已經(jīng)正確建立連接了,此時(shí)服務(wù)器通過accept返回的套接字來完成與客戶的通信。
注意:
accept默認(rèn)會(huì)阻塞進(jìn)程,直到有一個(gè)客戶連接建立后返回,它返回的是一個(gè)新可用的套接字,這個(gè)套接字是連接套接字。
此時(shí)我們需要區(qū)分兩種套接字,
監(jiān)聽套接字: 監(jiān)聽套接字正如accept的參數(shù)sockfd,它是監(jiān)聽套接字,在調(diào)用listen函數(shù)之后,是服務(wù)器開始調(diào)用socket()函數(shù)生成的,稱為監(jiān)聽socket描述字(監(jiān)聽套接字)
? ? 連接套接字:一個(gè)套接字會(huì)從主動(dòng)連接的套接字變身為一個(gè)監(jiān)聽套接字;而accept函數(shù)返回的是已連接socket描述字(一個(gè)連接套接字),它代表著一個(gè)網(wǎng)絡(luò)已經(jīng)存在的點(diǎn)點(diǎn)連接。
一個(gè)服務(wù)器通常通常僅僅只創(chuàng)建一個(gè)監(jiān)聽socket描述字,它在該服務(wù)器的生命周期內(nèi)一直存在。內(nèi)核為每個(gè)由服務(wù)器進(jìn)程接受的客戶連接創(chuàng)建了一個(gè)已連接socket描述字,當(dāng)服務(wù)器完成了對(duì)某個(gè)客戶的服務(wù),相應(yīng)的已連接socket描述字就被關(guān)閉。
連接套接字socketfd_new 并沒有占用新的端口與客戶端通信,依然使用的是與監(jiān)聽套接字socketfd一樣的端口號(hào)
2.5、recv()/send()函數(shù)
當(dāng)然也可以使用其他函數(shù)來實(shí)現(xiàn)數(shù)據(jù)傳送,比如read和write。
2.5.1send函數(shù)
ssize_t send(int sockfd, const void *buf, size_t len, int flags);不論是客戶還是服務(wù)器應(yīng)用程序都用send函數(shù)來向TCP連接的另一端發(fā)送數(shù)據(jù)。
客戶程序一般用send函數(shù)向服務(wù)器發(fā)送請(qǐng)求,而服務(wù)器則通常用send函數(shù)來向客戶程序發(fā)送應(yīng)答。
該函數(shù)的第一個(gè)參數(shù)指定發(fā)送端套接字描述符;
第二個(gè)參數(shù)指明一個(gè)存放應(yīng)用程序要發(fā)送數(shù)據(jù)的緩沖區(qū);
第三個(gè)參數(shù)指明實(shí)際要發(fā)送的數(shù)據(jù)的字節(jié)數(shù);
第四個(gè)參數(shù)一般置0。
這里只描述同步Socket的send函數(shù)的執(zhí)行流程。當(dāng)調(diào)用該函數(shù)時(shí),send先比較待發(fā)送數(shù)據(jù)的長(zhǎng)度len和套接字s的發(fā)送緩沖的 長(zhǎng)度,如果len大于s的發(fā)送緩沖區(qū)的長(zhǎng)度,該函數(shù)返回SOCKET_ERROR;如果len小于或者等于s的發(fā)送緩沖區(qū)的長(zhǎng)度,那么send先檢查協(xié)議是否正在發(fā)送s的發(fā)送緩沖中的數(shù)據(jù),如果是就等待協(xié)議把數(shù)據(jù)發(fā)送完,如果協(xié)議還沒有開始發(fā)送s的發(fā)送緩沖中的數(shù)據(jù)或者s的發(fā)送緩沖中沒有數(shù)據(jù),那么 send就比較s的發(fā)送緩沖區(qū)的剩余空間和len,如果len大于剩余空間大小send就一直等待協(xié)議把s的發(fā)送緩沖中的數(shù)據(jù)發(fā)送完,如果len小于剩余空間大小send就僅僅把buf中的數(shù)據(jù)copy到剩余空間里(注意并不是send把s的發(fā)送緩沖中的數(shù)據(jù)傳到連接的另一端的,而是協(xié)議傳的,send僅僅是把buf中的數(shù)據(jù)copy到s的發(fā)送緩沖區(qū)的剩余空間里)。如果send函數(shù)copy數(shù)據(jù)成功,就返回實(shí)際copy的字節(jié)數(shù),如果send在copy數(shù)據(jù)時(shí)出現(xiàn)錯(cuò)誤,那么send就返回SOCKET_ERROR;如果send在等待協(xié)議傳送數(shù)據(jù)時(shí)網(wǎng)絡(luò)斷開的話,那么send函數(shù)也返回SOCKET_ERROR。
要注意send函數(shù)把buf中的數(shù)據(jù)成功copy到s的發(fā)送緩沖的剩余空間里后它就返回了,但是此時(shí)這些數(shù)據(jù)并不一定馬上被傳到連接的另一端。如果協(xié)議在后續(xù)的傳送過程中出現(xiàn)網(wǎng)絡(luò)錯(cuò)誤的話,那么下一個(gè)Socket函數(shù)就會(huì)返回SOCKET_ERROR。(每一個(gè)除send外的Socket函數(shù)在執(zhí)行的最開始總要先等待套接字的發(fā)送緩沖中的數(shù)據(jù)被協(xié)議傳送完畢才能繼續(xù),如果在等待時(shí)出現(xiàn)網(wǎng)絡(luò)錯(cuò)誤,那么該Socket函數(shù)就返回 SOCKET_ERROR)
2.5.2recv函數(shù)學(xué)習(xí)
int recv( SOCKET s, char FAR *buf, int len, int flags ); 不論是客戶還是服務(wù)器應(yīng)用程序都用recv函數(shù)從TCP連接的另一端接收數(shù)據(jù)。 該函數(shù)的第一個(gè)參數(shù)指定接收端套接字描述符; 第二個(gè)參數(shù)指明一個(gè)緩沖區(qū),該緩沖區(qū)用來存放recv函數(shù)接收到的數(shù)據(jù); 第三個(gè)參數(shù)指明buf的長(zhǎng)度; 第四個(gè)參數(shù)一般置0。這里只描述同步Socket的recv函數(shù)的執(zhí)行流程。當(dāng)應(yīng)用程序調(diào)用recv函數(shù)時(shí),recv先等待s的發(fā)送緩沖中的數(shù)據(jù)被協(xié)議傳送完畢,如果協(xié)議在傳送s的發(fā)送緩沖中的數(shù)據(jù)時(shí)出現(xiàn)網(wǎng)絡(luò)錯(cuò)誤,那么recv函數(shù)返回SOCKET_ERROR,如果s的發(fā)送緩沖中沒有數(shù)據(jù)或者數(shù)據(jù)被協(xié)議成功發(fā)送完畢后,recv先檢查套接字s的接收緩沖區(qū),如果s接收緩沖區(qū)中沒有數(shù)據(jù)或者協(xié)議正在接收數(shù)據(jù),那么recv就一直等待,只到協(xié)議把數(shù)據(jù)接收完畢。當(dāng)協(xié)議把數(shù)據(jù)接收完畢,recv函數(shù)就把s的接收緩沖中的數(shù)據(jù)copy到buf中(注意協(xié)議接收到的數(shù)據(jù)可能大于buf的長(zhǎng)度,所以 在這種情況下要調(diào)用幾次recv函數(shù)才能把s的接收緩沖中的數(shù)據(jù)copy完。recv函數(shù)僅僅是copy數(shù)據(jù),真正的接收數(shù)據(jù)是協(xié)議來完成的),recv函數(shù)返回其實(shí)際copy的字節(jié)數(shù)。如果recv在copy時(shí)出錯(cuò),那么它返回SOCKET_ERROR;如果recv函數(shù)在等待協(xié)議接收數(shù)據(jù)時(shí)網(wǎng)絡(luò)中斷了,那么它返回0。
2.6、close()函數(shù)
在服務(wù)器與客戶端建立連接之后,會(huì)進(jìn)行一些讀寫操作,完成了讀寫操作就要關(guān)閉相應(yīng)的socket描述字,好比操作完打開的文件要調(diào)用fclose關(guān)閉打開的文件。
#include <unistd.h> int close(int fd);close一個(gè)TCP socket的缺省行為時(shí)把該socket標(biāo)記為以關(guān)閉,然后立即返回到調(diào)用進(jìn)程。該描述字不能再由調(diào)用進(jìn)程使用,也就是說不能再作為read或write的第一個(gè)參數(shù)。
注意:close操作只是使相應(yīng)socket描述字的引用計(jì)數(shù)-1,只有當(dāng)引用計(jì)數(shù)為0的時(shí)候,才會(huì)觸發(fā)TCP客戶端向服務(wù)器發(fā)送終止連接請(qǐng)求。
轉(zhuǎn)載于:https://www.cnblogs.com/zxouxuewei/p/5380621.html
總結(jié)
以上是生活随笔為你收集整理的linux中socket的理解---4的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 再回首Java第十一天
- 下一篇: 数据切分——Atlas读写分离Mysql