?????????Socket 是網(wǎng)絡(luò)協(xié)議棧暴露給編程人員的 API,相比復(fù)雜的計(jì)算機(jī)網(wǎng)絡(luò)協(xié)議,API 對(duì)關(guān)鍵操作和配置數(shù)據(jù)進(jìn)行了抽象,簡(jiǎn)化了程序編程。
? ? ? ? 本文講述的 socket 內(nèi)容源自 Linux man。本文主要對(duì)各 API 進(jìn)行詳細(xì)介紹,從而更好的理解 socket 編程。
shutdown(2)
遵循 POSIX.1-2008
1.庫(kù)
標(biāo)準(zhǔn) c 庫(kù),libc, -lc
2.頭文件
<sys/socket.h>
3.接口定義
int shutdown(int sockfd, int how);
4.接口描述
? ? ? ?shutdown() 調(diào)用會(huì)將 sockfd 指定的套接字上全雙工連接上的一端或者兩端關(guān)閉。如果 how 指定為 SHUT_RD,那么套接字上將不允許接收;如果 how 指定為 SHUT_WR,那么套接字上將不允許發(fā)送。如果 how 是 SHUT_RDWR,那么發(fā)送和接收都不允許。
5.返回值
? ? ? ?成功時(shí)返回 0,失敗返回 -1 并設(shè)置 errno。?
6.注意
? ? ? ? SHUT_RD、SHUT_WR、SHUT_RDWR 的值分別為 0、1、2,在 glibc-2.1.91 <sys/socket.h> 中定義。
? ? ? ? how 的合法性檢查會(huì)在相關(guān)的域代碼中進(jìn)行,但是 Linux 3.7 前并不是所有的域都會(huì)進(jìn)行可用性檢查。Linux 域套接字直接會(huì)忽略不可用的值,Linux 3.7 后這個(gè)問(wèn)題修復(fù)了。
?close(2)
遵頊 POSIX.1-2008
1.庫(kù)
標(biāo)準(zhǔn) c 庫(kù),libc, -lc
2.頭文件
<unistd.h>
3.接口定義
int close(int fd);
4.接口描述
? ? ? ?close() 會(huì)關(guān)閉一個(gè)文件描述符,關(guān)閉的描述符不再指向任何文件,關(guān)閉后可以重新使用該文件描述符。文件上和文件描述符相關(guān)的由該進(jìn)程所有的記錄鎖(參考 fcntl(2))將會(huì)被移除(不管是用哪個(gè)文件描述符獲得的該鎖)。
? ? ? ? 如果 fd 是最后一個(gè)指向底層打開(kāi)的文件描述的描述符(參考 open(2)),打開(kāi)文件描述的相關(guān)資源都會(huì)被釋放;如果文件描述符是最后一個(gè)指向通過(guò) unlink(2) 移除的文件,那么文件會(huì)被刪除。
5.返回值
? ? ? ?成功時(shí)返回 0,失敗返回 -1 并設(shè)置 errno。?
? ? ? ? 錯(cuò)誤列表如下:
? ? ? ? EBADF? ? ? ? fd 不是一個(gè)可用的文件描述符
? ? ? ? EINTR? ? ? ? ?close() 被中斷打斷;參考 signal(7)
? ? ? ? EIO? ? ? ? ? ? ? I/O 錯(cuò)誤發(fā)生
? ? ? ? ENOSPE、EDQUOT
? ? ? ? ? ? ? ? 在 NFS 上,第一次超出可用空間的寫(xiě)不會(huì)報(bào)告這些錯(cuò)誤,而是在接下來(lái)的 write(2)、fsync(2) 或者 close(2) 時(shí)報(bào)告這些錯(cuò)誤??梢詤⒖甲⒁獠糠植榭礊槭裁?close() 在報(bào)錯(cuò)后不能再次重試。
6.注意
? ? ? ? 成功關(guān)閉文件描述符并不保證數(shù)據(jù)成功同步到磁盤(pán)上,因?yàn)閮?nèi)核會(huì)使用緩沖區(qū)來(lái)做延遲寫(xiě)。通常情況下,文件系統(tǒng)不會(huì)在文件關(guān)閉時(shí)同步這些緩沖區(qū)到磁盤(pán)上。如果我們想確信數(shù)據(jù)被存儲(chǔ)到底層磁盤(pán),使用 fsync(2) 先進(jìn)行同步。(從這一點(diǎn)上,也依賴磁盤(pán)硬件)。
? ? ? ? 如果文件描述符標(biāo)記指定了 close-on-exec,那么就可以保證文件在執(zhí)行 execve(2) 時(shí)自動(dòng)關(guān)閉。參考 fcntl(2) 查看詳細(xì)信息。
? ? ? ? 多線程進(jìn)程和 close()
? ? ? ? 一個(gè)進(jìn)程中如果有其他線程在使用系統(tǒng)調(diào)用訪問(wèn)文件描述符,那么通過(guò) close 關(guān)閉文件描述符是非常不明智的。因?yàn)槲募枋龇梢灾赜?,一些條件競(jìng)爭(zhēng)就可能會(huì)導(dǎo)致一些意想不到的結(jié)果。
? ? ? ? 此外,我們可以考慮下面兩個(gè)線程操作同一個(gè)文件描述符的場(chǎng)景:
? ? ? ? (1)一個(gè)線程正在阻塞在文件描述符的系統(tǒng)調(diào)用上,比如向一個(gè)滿了的管道嘗試 write(2) 寫(xiě),或者從一個(gè)沒(méi)有數(shù)據(jù)的流套接字上 read(2) 讀。
? ? ? ? (2)另一個(gè)線程關(guān)閉這個(gè)文件描述符
? ? ? ? 這種情況在不同的系統(tǒng)上的行為是不一樣的,一些系統(tǒng)上一旦文件描述符關(guān)閉,其他阻塞系統(tǒng)調(diào)用就會(huì)返回錯(cuò)誤。
? ? ? ? 在 Linux 以及另一個(gè)系統(tǒng)上,行為是不同的:阻塞的 I/O 系統(tǒng)調(diào)用一直持有底層打開(kāi)的文件描述,直到 I/O 系統(tǒng)調(diào)用結(jié)束。(參考 open(2) 關(guān)于打開(kāi)文件描述的討論。)因此,阻塞系統(tǒng)調(diào)用完全可能在 close() 后仍然成功返回。
? ? ? ? close() 返回錯(cuò)誤處理
? ? ? ? 編程人員需要檢查 close() 的返回值,因?yàn)楹芸赡苤?write(2) 的錯(cuò)誤只能在最后的 close() 要釋放文件描述時(shí)才會(huì)報(bào)告。不檢查錯(cuò)誤返回值可能會(huì)導(dǎo)致一些數(shù)據(jù)偷偷的丟掉,這種情況在 NFS 和磁盤(pán)配額時(shí)是常見(jiàn)的。
? ? ? ? 然而這些錯(cuò)誤返回值只能用來(lái)診斷(即向應(yīng)用發(fā)出警告:可能仍然有一些等待的 I/O 或者 I/O 失敗)以及重播目的(即再寫(xiě)一次文件或者創(chuàng)建備份)。
? ? ? ? 失敗后重試 close() 是不可行的,因?yàn)槲募枋龇赡軙?huì)被其他線程重用,導(dǎo)致誤關(guān)閉其他線程文件描述符,這主要是因?yàn)閮?nèi)核會(huì)首先釋放文件描述符,然后再進(jìn)行一些會(huì)返回錯(cuò)誤的操作,比如將數(shù)據(jù)刷新到文件系統(tǒng)或設(shè)備。
? ? ? ? 一些其他系統(tǒng)實(shí)現(xiàn)也會(huì)再報(bào)告錯(cuò)誤的情況下關(guān)閉文件描述符(除了 EBADF,表示文件描述符不可用)。POSIX.1 目前對(duì)這點(diǎn)并沒(méi)有提出什么,不過(guò)可能在下一個(gè)主版本會(huì)授權(quán)這種做法。
? ? ? ? 我們可以通過(guò)在發(fā)生錯(cuò)誤的 close(2) 后調(diào)用 fsysnc(2) 來(lái)了解具體是發(fā)生了什么 I/O 錯(cuò)誤。
? ? ? ? EINTR 錯(cuò)誤有點(diǎn)特殊,關(guān)于這個(gè)錯(cuò)誤,POSIX.1-2008 的說(shuō)法是:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-713373.html
如果 close() 被能被捕捉到的信號(hào)中斷,它應(yīng)該返回 -1 并將 errno 設(shè)置為 EINTR,fildes 狀態(tài)未指定
? ? ? ? 這就允許 Linux 以及其他實(shí)現(xiàn)上可以像處理其他錯(cuò)誤一樣處理這個(gè)錯(cuò)誤,文件描述符保證被關(guān)閉了。然而,也允許返回 EINTR 后仍然保持文件描述符是打開(kāi)的。(HP-UX 的 close() 就是這樣的。)調(diào)用者必須重新使用 close() 來(lái)關(guān)閉文件描述符,避免文件描述符泄露。這種實(shí)現(xiàn)的不同導(dǎo)致了程序移植性問(wèn)題,因?yàn)槠渌麑?shí)現(xiàn)在失敗后不允許重新 close()。下一個(gè) POSIX.1 的主版本也會(huì)解決這個(gè)問(wèn)題。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-713373.html
到了這里,關(guān)于【計(jì)算機(jī)網(wǎng)絡(luò)】網(wǎng)絡(luò)編程接口 Socket API 解讀(11)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!