【計(jì)算機(jī)網(wǎng)絡(luò)】Socket

Socket 介紹

概述

socket是一種IPC方法辩块,它允許位于同一主機(jī)或使用網(wǎng)絡(luò)連接起來的不同主機(jī)的應(yīng)用程序之間交換數(shù)據(jù)锉走。

socket進(jìn)行通信的方式如下:

  • 各個應(yīng)用程序創(chuàng)建一個socket以清,socket是一個允許通信的“設(shè)備”弥鹦,兩個應(yīng)用程序都需要用到它戏挡。
  • 服務(wù)器將自己的socket綁定到一個眾所周知的地址上使得客戶端能夠定位到它的位置固逗。

使用socket()系統(tǒng)調(diào)用能夠創(chuàng)建一個socket,它返回一個用來在后續(xù)系統(tǒng)調(diào)用中引用該socket的文件描述符拘领。

fd = socket(domain, type, protocol)

通信domain

socket存在于一個通信domain中淋纲,它確定:

  • 識別出一個socket的方法(即socket“地址”的格式)
  • 通信范圍(是同一主機(jī),還是網(wǎng)絡(luò)中不同主機(jī))

現(xiàn)在操作系統(tǒng)支持下列domain:

  • UNIX(AF_UNIX)domain:允許同一主機(jī)上的應(yīng)用程序之間進(jìn)行通信
  • IPv4(AF_INET)domain
  • IPv6(AF_INET6)domain
socket domain

socket類型

每個socket實(shí)現(xiàn)都至少提供了兩種socket:流和數(shù)據(jù)報院究。這兩種類型在UNIX和Internet domain中都得到了支持洽瞬。

socket 類型及其屬性
流socket(SOCK_STREAM)

流socket提供了一個可靠的雙向的字節(jié)流通信信道:

  • 可靠的
  • 雙向的
  • 字節(jié)流
數(shù)據(jù)報socket(SOCK_DGRAM)

數(shù)據(jù)報socket允許數(shù)據(jù)以數(shù)據(jù)報的形式進(jìn)行交換。在使用時無需與另一個socket簡歷連接业汰。

socket 系統(tǒng)調(diào)用

socket()
int socket(domain, type, protocol)
  • 創(chuàng)建一個新的socket
  • type 指定socket類型伙窃,創(chuàng)建流socket通常指定為 SOCK_STREAM,數(shù)據(jù)報socket指定為SOCK_DGRAM
  • protocol默認(rèn)為0
  • 返回socket的文件描述符
bind()
int bind(sockfd, struct sockaddr *addr, socklen_t addrlen)
  • 將一個socket綁定到一個地址上样漆,通常为障,服務(wù)器需要使用這個調(diào)用來將其socket綁定到一個地址上供客戶端能夠定位到該socket上
  • addr參數(shù)是一個指針,指向socket綁定到的地址結(jié)構(gòu)上放祟,這個參數(shù)的結(jié)構(gòu)類型取決于domain鳍怨。
  • 服務(wù)器可以不調(diào)用bind()直接調(diào)用listen(),這將會導(dǎo)致內(nèi)核為該socket選擇一個臨時端口
  • 客戶端一般不需要調(diào)用跪妥,操作系統(tǒng)會自動綁定
通用socket地址結(jié)構(gòu):struct sockaddr

傳入bind()的addr比較復(fù)雜鞋喇,每種socket domain都使用了不同的地址格式,如UNIX domain socket使用路徑名眉撵,而Internet domain socket 使用IP地址和端口號侦香。struct sockaddr適用于所有domain,將各種domain特定的地址結(jié)構(gòu)轉(zhuǎn)換成單個類型以供socket系統(tǒng)調(diào)用中的各個參數(shù)使用纽疟。

Paste_Image.png
listen()
  • 允許一個流socket接受來自其他socket的接入連接
accept()
  • 在一個監(jiān)聽流socket上接受來自一個對等應(yīng)用程序的連接罐韩,并可選的返回對等socket地址
connect()
  • 簡歷與另一個socket之間的連接

在大多數(shù)Linux架構(gòu)上污朽,所有這些socket系統(tǒng)調(diào)用實(shí)際上被實(shí)現(xiàn)成了通過單個系統(tǒng)調(diào)用socketcall()進(jìn)行多路復(fù)用的庫函數(shù)。

socket I/O 可以使用傳統(tǒng)的read()和write()系統(tǒng)調(diào)用或使用一組socket特有的系統(tǒng)調(diào)用send() recv() sendto() recvfrom()矾睦。默認(rèn)情況下晦款,這些系統(tǒng)調(diào)用在I/O操作無法被立即完成時阻塞,使用fcntl() F_SETFL 操作用啟用 O_NONBLOCK 打開文件狀態(tài)標(biāo)記可以執(zhí)行非阻塞I/O

流socket

流程
  • 每個應(yīng)用程序都必須創(chuàng)建一個socket
  • 服務(wù)端程序調(diào)用bind()將socket綁定到一個地址上柬赐,然后調(diào)用listen()通知內(nèi)核它接受接入連接的意愿官紫。
  • 其他客戶端程序通過connect()建立連接,同時指定需連接的socket的地址
  • 服務(wù)端程序使用accept()接受連接州藕。
  • 建立連接后束世,進(jìn)行雙向數(shù)據(jù)傳輸直到其中一個使用close()關(guān)閉連接為止床玻。
  • 通信是通過傳統(tǒng)的read()和write()系統(tǒng)調(diào)用或通過額外的一些socketAPI(send() recv())
流socket系統(tǒng)調(diào)用流程
監(jiān)聽接入連接:listen()
int listen(sockfd, backlog)

listen()系統(tǒng)調(diào)用將文件描述符sockfd引用的流socket標(biāo)記為被動锈死,這個socket后面會被用來接受來自其他(主動的)socket的鏈接。

無法再一個已連接的socket(已成功執(zhí)行connect()的socket或由accept()調(diào)用返回的socket)上執(zhí)行 listen()

如果服務(wù)器正忙于處理其他客戶端其屏,那么客戶端的connect()可能并不能馬上被accept()缨该,這將產(chǎn)生一個未決的連接贰拿。

一個未決的socket連接

內(nèi)核必須要記錄所有未決的連接請求的相關(guān)信息,backlog參數(shù)允許限制這種未決連接的數(shù)量妙真。在這個限制之內(nèi)的連接請求會立即成功荚守,之外的連接請求就會阻塞直到一個未決的連接被接受,并從未決連接隊(duì)列中刪除健蕊。

接受連接:accept()
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)

accept()系統(tǒng)調(diào)用會文件描述符sockfd引用的監(jiān)聽流socket上接受一個連入連接缩功。如果在調(diào)用accept時不存在未決的連接,那么調(diào)用會阻塞直到有連接請求到達(dá)為止虑稼。

返回的結(jié)果是已連接的socket的文件描述符。addr參數(shù)指向一個用來返回socket地址的結(jié)構(gòu)歌懒。

連接到對等socket:connect()
int connect()
流socket I/O

一對連接的流 socket 在兩個端點(diǎn)之間提供了一個雙向通信信道溯壶。

雙向通信信道
連接終止:close()

關(guān)閉一個連接之后且改,對等應(yīng)用程序讀取數(shù)據(jù)時將會收到文件結(jié)束(所有緩沖數(shù)據(jù)都讀取之后),如果要寫入數(shù)據(jù)碍拆,會收到一個SIGPIPE信號感混,并且系統(tǒng)調(diào)用返回EPIPE錯誤礼烈。

數(shù)據(jù)報 socket

流程
  • 需要發(fā)送和接受數(shù)據(jù)報的應(yīng)用程序都需要使用socket()創(chuàng)建一個數(shù)據(jù)報socket
  • 服務(wù)器將socket綁定到IP地址上,客戶端通過該地址發(fā)起通信谱秽。
  • 要發(fā)送一個數(shù)據(jù)報摹迷,客戶端調(diào)用sendto()
  • 服務(wù)端調(diào)用recvfrom()峡碉,在沒有數(shù)據(jù)報時會阻塞。
  • 不再需要是吉执,調(diào)用close()

無法保證順序地来,也無法保證能夠到達(dá)未斑。由于底層協(xié)議有時會重新傳包,也可能多次到達(dá)府阀。

數(shù)據(jù)報流程
交換數(shù)據(jù)報 recvfrom() sendto()
在數(shù)據(jù)報socket上使用connect()

盡管數(shù)據(jù)報socket是無連接的试浙,但在數(shù)據(jù)報socket上應(yīng)用connect()系統(tǒng)調(diào)用仍然起作用,會導(dǎo)致內(nèi)核記錄這個socket的對等socket地址钠糊。

當(dāng)一個數(shù)據(jù)報socket已連接后:

  • 數(shù)據(jù)報的發(fā)送可在socket上使用write和send

Socket UNIX DOMAIN

UNIX domain socket地址:struct sockaddr_un

在UNIX domain中固额,socket地址以路徑名來表示斗躏,domain特定的socket地址結(jié)構(gòu)的定義如下:

結(jié)構(gòu)

為將一個UNIX domain socket綁定到一個地址上啄糙,需要初始化一個sockaddr_un結(jié)構(gòu)云稚,然后將指向這個結(jié)構(gòu)的一個指針作為addr參數(shù)傳入bind()并將addrlen指定為這個結(jié)構(gòu)的大小。

當(dāng)用來綁定UNIX domain socket時燕雁,bind()會在文件系統(tǒng)中創(chuàng)建一個條目拐格,作為socket路徑名的一部分的目錄需要可訪問和可寫刑赶。這個文件會被標(biāo)記為一個socket,當(dāng)再這個路徑名上應(yīng)用stat()時金踪,它會在stat結(jié)構(gòu)的st_mode字段中的文件類型部分返回值S_IFSOCK胡岔。

盡管UNIX domain socket是通過路徑名來標(biāo)識的枷餐,但這些socket上發(fā)生的I/O無須對底層設(shè)備進(jìn)行操作。

有關(guān)綁定一個UNIX domain socket的注意點(diǎn):

  • 無法將一個socket綁定到一個既有路徑名上
  • 通常將一個socket綁定到一個絕對路徑上奕锌,這樣這個socket就會位于文件系統(tǒng)中的一個固定地址處
  • 一個socket只能綁定一個路徑名
  • 無法使用open()打開一個socket
  • 當(dāng)不再需要一個socket時可以使用unlink()刪除其路徑條目

UNIX domain中的流socket

服務(wù)器流程:

  • 創(chuàng)建一個socket
  • 刪除所有與路徑名一致的既有文件惊暴,這樣就能將socket綁定到這個路徑名上
  • 為服務(wù)器socket構(gòu)建一個地址結(jié)構(gòu),將socket綁定到該地址上肄鸽,將這個socket標(biāo)記為監(jiān)聽socket
  • 執(zhí)行一個無線循環(huán)來處理進(jìn)入的客戶請求油啤,每次循環(huán)迭代執(zhí)行以下任務(wù):
    • 接受一個連接益咬,為該連接獲取一個新的socket cfd
    • 從已連接的socket中讀取所有數(shù)據(jù)并將這些數(shù)據(jù)寫入到標(biāo)準(zhǔn)輸出中
    • 關(guān)閉已連接的socket cfd
  • 服務(wù)器手動終止(發(fā)送一個信號)

客戶端流程:

  • 創(chuàng)建一個socket
  • 為服務(wù)器socket構(gòu)建一個地址并連接到位于該地址處的socket
  • 執(zhí)行一個循環(huán),將其標(biāo)準(zhǔn)輸入復(fù)制到socket連接上梅鹦,當(dāng)遇到標(biāo)準(zhǔn)輸入中的文件結(jié)尾時客戶端就終止齐唆,其結(jié)果是客戶端socket將會關(guān)閉并且服務(wù)器從連接的另一端的socket中讀取數(shù)據(jù)時會看到文件結(jié)束冻河。

UNIX domain中的數(shù)據(jù)報socket

對于UNIX domain socket來說叨叙,數(shù)據(jù)報的傳輸是在內(nèi)核中發(fā)生的,也是可靠的廷蓉,所有消息都會按序被遞送并且不會發(fā)生重復(fù)的狀況马昙。

服務(wù)器創(chuàng)建socket后并綁定后,進(jìn)入一個無線循環(huán)攒暇,在循環(huán)中使用recvfrom()接收來自客戶端的數(shù)據(jù)報形用,將接收到的文本轉(zhuǎn)換成大小格式并使用通過recvfrom()獲取的地址將轉(zhuǎn)換過的文本返回給客戶端。

UNIX domain socket權(quán)限

socket文件的所有權(quán)和權(quán)限決定了哪些進(jìn)程能夠與這個socket進(jìn)行通信

  • 要連接一個UNIX domain流socket需要在該socket文件上擁有寫權(quán)限
  • 要通過一個UNIX domain數(shù)據(jù)報socket發(fā)送一個數(shù)據(jù)報需要在該socket文件上擁有寫權(quán)限
  • 需要在存放socket路徑名的所有目錄上都擁有執(zhí)行權(quán)限

創(chuàng)建互聯(lián)socket對:socketpair()

有時候讓單個進(jìn)程創(chuàng)建一對socket并將它們連接起來是比較有用的妒御。

int socketpair(int domain, int type, int protocol, int sockfd[2])

Linux抽象socket名空間

允許將一個UNIX domain socket綁定到一個名字上但不會在文件系統(tǒng)中創(chuàng)建的名字

  • 無需擔(dān)心與文件系統(tǒng)中的既有名字產(chǎn)生沖突
  • 沒有必要在使用完socket之后刪除socket路徑名乎莉,當(dāng)socket被關(guān)閉之后會自動刪除這個抽象名
  • 無需為socket創(chuàng)建一個文件系統(tǒng)路徑名了奸笤,這對于chroot緩解以及在不具備文件系統(tǒng)上的寫權(quán)限時比較有用的监右。

SOCKET:TCP/IP 網(wǎng)絡(luò)基礎(chǔ)

網(wǎng)絡(luò)協(xié)議和層

TCP/IP套件中的協(xié)議
分層通信
TCP/IP協(xié)議層中的封裝

數(shù)據(jù)鏈路層

要傳輸數(shù)據(jù)健盒,數(shù)據(jù)鏈路層需要將網(wǎng)絡(luò)層傳遞過來的數(shù)據(jù)報封裝進(jìn)被稱為幀的一個一個單元味榛。最大傳輸單元MTC是改層所能傳輸?shù)膸笮〉纳舷蕖?/p>

網(wǎng)絡(luò)層 IP

網(wǎng)絡(luò)層任務(wù):

  • 將數(shù)據(jù)分解成足夠小的片段以便數(shù)據(jù)鏈路層進(jìn)行傳輸
  • 在因特網(wǎng)上路由數(shù)據(jù)
  • 為傳輸層提供服務(wù)

網(wǎng)絡(luò)層的協(xié)議是IP予跌,IPv4使用32位地址來標(biāo)識子網(wǎng)和主機(jī)券册,IPv6則使用了128位的地址。

一個裸socket(SOCK_RAW),允許程序直接與IP層進(jìn)行通信航邢,但大多數(shù)都會基于一種傳輸層協(xié)議之上的socket骄蝇。

IP傳輸數(shù)據(jù)報

IP以數(shù)據(jù)報(包)的形式來傳輸數(shù)據(jù)九火。在兩個主機(jī)之間發(fā)送的每一個數(shù)據(jù)報都是在網(wǎng)絡(luò)上獨(dú)立傳輸?shù)模鼈兘?jīng)過的路徑可能會不同勒极。一個IP數(shù)據(jù)報包含一個頭虑鼎,其大小范圍為20字節(jié)到60字節(jié)。包含目標(biāo)主機(jī)的地址絮短,源地址昨忆。

一個IP實(shí)現(xiàn)可能會給它所支持的數(shù)據(jù)報的大小設(shè)定一個上限。所有IP實(shí)現(xiàn)都必須做到數(shù)據(jù)報的大小上限至少與規(guī)定的IP最小重組緩沖區(qū)大小一樣大限府。IPv4限制值是576字節(jié)胁勺,IPv6是1500字節(jié)独旷。

IP是無連接和不可靠的

IP是一種無連接協(xié)議,并沒有在相互連接的兩個主機(jī)之間提供一個虛擬電路案疲。

IP是一種不可靠的協(xié)議:盡最大可能將數(shù)據(jù)報從發(fā)送者傳輸給接收者褐啡,但并不保證包到達(dá)的順序與它們被傳輸?shù)捻樞蛞恢卤畈膊槐WC是否重復(fù)许昨,甚至到達(dá)。IP也美譽(yù)錯誤恢復(fù)莉恼∷倌牵可靠性是通過使用TCP來保證的琅坡。

IPv4為IP頭提供了一個校驗(yàn)和,這樣能夠檢測出頭中的錯誤售躁,但并沒有為包中所傳輸?shù)臄?shù)據(jù)提供任何錯誤檢測機(jī)制。IPv6并沒有為IP頭提供校驗(yàn)和回窘,它依賴高層協(xié)議來完成錯誤檢測和可靠性市袖。

IP數(shù)據(jù)報的重復(fù)使可能發(fā)生的苍碟,數(shù)據(jù)鏈路層采用一些技術(shù)確保可靠性以及IP數(shù)據(jù)報可能會以隧道形式穿越采用了重傳機(jī)制舷丹。

IP對數(shù)據(jù)報進(jìn)行分段

IP會將數(shù)據(jù)報分段成一個個大小合適的傳輸單元颜凯,這些分段在到達(dá)最終目的之后會被重組成原始的數(shù)據(jù)報(每個IP分段本身就包含一個偏移量)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末症概,一起剝皮案震驚了整個濱河市早芭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌精肃,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件黎烈,死亡現(xiàn)場離奇詭異匀谣,居然都是意外死亡武翎,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進(jìn)店門符隙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來霹疫,“玉大人,你說我怎么就攤上這事猎拨『焓。” “怎么了国觉?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵蛉加,是天一觀的道長。 經(jīng)常有香客問我厂抽,道長筷凤,這世上最難降的妖魔是什么苞七? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任蹂风,我火速辦了婚禮惠啄,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘融柬。我一直安慰自己趋距,他們只是感情好节腐,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著骡澈,像睡著了一般掷空。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上护锤,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天烙懦,我揣著相機(jī)與錄音赤炒,去河邊找鬼莺褒。 笑死,一個胖子當(dāng)著我的面吹牛你辣,可吹牛的內(nèi)容都是我干的舍哄。 我是一名探鬼主播誊锭,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼炉旷,長吁一口氣:“原來是場噩夢啊……” “哼窘行!你這毒婦竟也來了图仓?” 一聲冷哼從身側(cè)響起救崔,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎纬黎,沒想到半個月后本今,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年躏碳,在試婚紗的時候發(fā)現(xiàn)自己被綠了菇绵。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片镇眷。...
    茶點(diǎn)故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡偏灿,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出铆遭,到底是詐尸還是另有隱情枚荣,我是刑警寧澤啼肩,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布祈坠,位于F島的核電站,受9級特大地震影響慌随,放射性物質(zhì)發(fā)生泄漏阁猜。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一黄刚、第九天 我趴在偏房一處隱蔽的房頂上張望憔维。 院中可真熱鬧研铆,春花似錦棵红、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽素征。三九已至,卻和暖如春根欧,著一層夾襖步出監(jiān)牢的瞬間凤粗,已是汗流浹背今豆。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工呆躲, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留插掂,地道東北人应役。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像燥筷,于是被迫代替她去往敵國和親箩祥。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評論 2 350

推薦閱讀更多精彩內(nèi)容

  • iPhone的標(biāo)準(zhǔn)推薦是CFNetwork 庫編程肆氓,其封裝好的開源庫是 cocoa AsyncSocket庫袍祖,用它...
    Ethan_Struggle閱讀 2,230評論 2 12
  • 名詞延伸 通俗的說凳鬓,域名就相當(dāng)于一個家庭的門牌號碼,別人通過這個號碼可以很容易的找到你患民。如果把IP地址比作一間房子...
    楊大蝦閱讀 20,592評論 2 57
  • Socket創(chuàng)建函數(shù) socket.socket(socket_family, socket_type, prot...
    JianMing閱讀 6,007評論 1 13
  • 原文地址:http://www.cnblogs.com/skynet/archive/2010/12/12/190...
    archyly閱讀 1,060評論 0 8
  • 最近在學(xué)習(xí)Python看了一篇文章寫得不錯缩举,是在腳本之家里的,原文如下匹颤,很有幫助: 一仅孩、網(wǎng)絡(luò)知識的一些介紹 soc...
    qtruip閱讀 2,692評論 0 6