TCP和Socket通訊原理詳解

Web: web

TCP/IP算法

DARPA項目研發的以太網瀏覽器

TCP/IP劃分的層次緩存

clip_image002

把互聯網通訊分層的緣由:互聯網通訊是很複雜的事情,他們彼此之間數據、包括涉及到在物理層次上如何控制這種電氣序列的傳輸、電平信號的傳輸以及包含咱們如何將數據報文從源端到達目的端、還有若是咱們將一個數據分隔成好幾個部分來進行傳輸,那麼數據誰是第一個、誰是第二個等?在接收方接收到之後如何進行整合?等等,這是一件很是複雜的事情,計算機通訊也和人類通訊同樣,其也須要一種語言,所以計算機通訊所用的語言也就是咱們常接觸到的協議,指的是雙方通訊時共同遵循的規範,也即發送方說的接收都能理解,按照發送方的原生目的將數據接收下來並實現存儲,因爲此過程很是複雜因此被分割成多個階段的不一樣層次來進行完成,用於實現不一樣的功能。服務器

在TCP/IP模型中,其中設備驅動程序和硬件這個層次,主要用來負責物理設備在實現通訊時,如何傳送電氣信號?如何傳送高低電平?如何儘量的讓兩者實現同步或者異步的方式實現無差錯的數據傳輸等等?使用大端方式仍是小端方式?網絡

所謂大端方式:就是數據存儲時,咱們要存儲一個整數,整數要轉換爲二進制以後,他有以十進制爲例有十位、百位、萬位等,可是在網絡上數據傳輸或者在計算機上數據存儲其必定是一位一位存的,而不是把全部數據都擠到內存中或者網絡上,所以要存儲一個十進制數據或者存儲一個整數時,究竟是先存最高位仍是先存最低位?架構

先存最低位的是叫作小端、先存最高位的叫作大端。併發

互聯網上不一樣的架構主機其存儲方式是不一樣的,X86架構存儲的多是小端的,其餘的服務器存儲時可能用到的是大端的,因此爲了保證這些不一樣主機在互聯網上交互時也可以彼此之間互相傳輸數據,在網絡上實現的協議就要規定你傳數據時,是先傳大端的仍是先傳小端的?這些規定就是協議中應該要完成的事情,設備驅動程序和硬件就要解決諸如此類的問題。dom

再向上一層,網絡層上有IPv4和IPv6,咱們稱爲ip報文,ip報文層次上主要是如何傳輸的呢?設備驅動程序和硬件主要用來實現平面化的同一個物理網絡中的硬件之間的通訊,因此在面向特別大的網絡時他們就無能爲力了,用IPv4和IPv6實現邏輯地址,將主機上地址分紅了三維空間,因此有了所謂的網絡地址、所謂的主機地址。主機地址到了之後,再轉換成對應MAC地址彼此之間進行通訊。可是ip報文自己是不可靠的,他僅僅是一個報文,從發送方到接收方而已。若是說某一個ip報文發送到中途的時候因爲網絡故障緣由丟失了怎麼辦?咱們是否進行重傳、以及咱們如何知道ip報文處在通訊過程中?咱們知道若是說傳輸數據有20M,ip報文所可以承載的數據量是很小的,那如何把這個數據分隔成了多個報文?並且那些報文應該合併起來重組成同一個文件呢?因此ip協議在這個層次上是沒法完成此類功能的,它僅僅是實現邏輯地址空間的鑑定。如何實現所謂的數據發送報文發送的序列序列化定製?則須要藉助更高的或者其餘額外的功能,這個額外的功能沒有在ip報文實現而是在另一個層次上實現了,這些諸多功能的實現他們分別使用了不一樣的層次來完成,這樣每個層次只須要將他所須要提供功能向上提供一個接口,每個層次用接口的方式向上層輸出,同時每個層次又調用下一層的接口所提供的功能,未來其中任何一個層次發生了改變,只要提供的接口和向下層的調用沒有發生改變,那麼任何一個層次的改變都不會牽一髮而動全身,好比IPv4的版本升級爲IPv6,只要IPv6繼續要上層提供服務,向下層調用對應的功能,那麼仍然不會受到影響,下層不用作修改,tcp、udp也不用作修改,使得一個大問題被分解成了n個小問題,每一個小問題均可以獨立維護和解決。這也是模塊化的一種表現。ip層次主要提供的功能就是封裝。ssh

tcp層次提供的功能:

序列化的報文傳輸;

若是兩個通訊主機節點的性能不一樣,一端發送速度很快,而另外一端接收速度很是慢,會發生什麼問題呢?發送方的快速傳輸會瞬間把接收方給淹沒,因此會致使大量的報文丟失,所以爲避免此種狀況,應該如何作?要作傳輸控制,tcp【是傳輸控制協議】

udp也實現了相似tcp同樣的功能,tcp和udp還有另一個特色:他們能夠實如今本機上爲本機的進程提供地址,tcp和udp使用一個16位的二進制數來表示進程地址,只不過一般把這個整數稱做端口號。因此本機上的真正的通訊進程要想可以跟其餘主機上的進程之間進行通訊時,那爲了標識當前主機上的哪個進程跟另一個主機上的哪個進程通訊,tcp就經過端口的方式爲這些進程提供地址,用16位二進制表示的整數進行標記。

clip_image004

在對應右側即爲能夠對等同樣的黑線,表示不一樣的實現位置,應用層協議是真正負責實現數據傳輸時完成真正的通訊目的的層次,底下層次主要是爲了能讓報文從源端發往目的端,發往目的端後,怎麼應用?怎麼去理解裏面報文?怎麼存儲?對方要請求仍是咱們要響應?等等,其實都是在應用層進行規定的,好比WEB服務爲例,咱們是在瀏覽器上輸入一個地址請求對方傳輸一個網頁,對方即把網頁傳輸過來,可是對方網站上的網頁可能不止一個,咱們請求的可能只是某一次請求當中的一個,那對方如何知道咱們請求的哪個網頁呢?tcp、udp中是沒有標記的,tcp/udp提供的僅僅是進程地址標識,ip僅僅是用來傳輸報文的。那麼請求的是哪個網頁應該是由應用層來定義的,應用層實現的是:如咱們要完成特定功能,兩者之間如何交互?我這邊是請求仍是響應,並且請求是使用什麼方法來進行的,web服務請求包括從網站上拉一個網頁在本地顯示,也包括在本地打開一個表當填寫一些數據,提交到服務器端上保存下來,web服務容許咱們上傳一些文件,因此這些在同一種應用中,或者叫web服務當中也有不少不一樣的功能,這每一種功能都須要在應用層實現,因此應用層也有應用層協議。web是一種應用層協議【打開網頁的】、ftp【上傳和下載文件的】、SMTP【發送郵件的】、dns【讓咱們能發出名稱解析請求,並能接受對方的響應的】等等,因此他們都須要各自有各自的不一樣功能,就像操做系統同樣,底下用來提供公共功能,而上面用來提供具體的應用的,像操做系統也是,底層是一層操做系統,它並不提供具體的特定功能,自己不產生生產力,真正產生生產力的是應用程序。因此應用程序是爲了完成某一應用的特定應用程序。網絡模型中也是遵循此法則的,能夠理解底層爲網絡操做系統,網絡通用層。上一層爲網絡的具體應用,應用層。這些層次通用的功能就是在系統內核中實現的,而所謂應用層應用都是在用戶進程實現的,他們對應了操做系統模型,這些通用功能都在內核中實現,也即知道內核中包括了網絡的功能。底層的三層也稱爲通訊子網,他主要考慮這個報文不管是dns查詢請求報文、web服務的資源請求報文,它只關心請求如何從這端傳遞給通訊的對端。也即只關心通訊細節是在內核中負責實現的,所以任何用戶進程指望經過tcp或udp並藉助ip這種方式實現通訊那麼只須要向內核中的網絡子功能發起系統調用接口,用戶進程實現了真正負責完成須要通訊時的某一種特定應用,在操做系統上全部用戶進程當中有些並不須要網絡通訊,好比ls不須要,用戶進程當中並不是每個都要用到內核當中的網絡子功能,但有些須要好比ssh,scp等,須要藉助網絡和對等的對端上某一個進程進行通訊,像ssh客戶端和sshd服務器端能夠通訊,兩者之間能夠創建會話,因此有些進程要想可以實現通訊要向內核中的通訊子功能發起系統調用,好比請求對方創建ssh會話的報文發給內核中的tcp層,tcp層爲了將報文可靠的傳輸給另一個主機須要封裝tcp首部、一樣要封裝ip報文藉助ip這種機制進行傳輸,最終被調製爲硬件上的高低電平信號在網絡上傳輸,對方把高低電平信號接收後,還原爲ip報文,再還原爲tcp報文,再還原爲應用層數據,最終被對方接收到。

其實在兩個主機上的兩個進程之間爲了可以完成通訊,其中任何一個主機必然一個是主動方,一個是被動方。除非是點對點之間的通訊,可是不是此處考慮的問題,因此必須有一個主動打開方,一個被動打開方。而事實上被動打開端被稱爲服務器端,由於其隨時等待客戶端請求,並與對方創建鏈接完成通訊,因此被動打開端被稱爲監聽的一方,一般要監聽在某一個地址上,注意必定要有一個地址,不然對方來請求時,65535個地址不知道是哪個,因此請求方必需要知道請求的是對方主機上的哪個進程,那如何知道對方主機上的哪個進程要和本身通訊?進程是被動打開的等待來訪問的,就要使用衆所周知的端口,就意味着互聯網上的IANA有規定,哪個端口是負責ssh通訊的【22號】,若是把sshd監聽在非22號端口了,客戶端請求就不知道是哪個端口了,因此被動打開就是打開一個衆所周知的你們約定都認識的端口上。而套接字就是創建在應用層和tcp層之間,因此某一個進程在服務器端打算要在某一端口等待客戶端創建請求,應用程序能夠任意使用這些端口,不論這些端口是否使用都有,任意一個進程要真正使用時要向內核發起申請,要使用哪一個端口,要監聽在哪一個端口上。若是有人發數據給這個端口,則進程就能夠接收對應的數據了。內核接收到一個報文說要請求22號端口,若是沒有任何進程註冊使用22號端口、沒有任何進程說明了要在22號端口上打開。那麼內核接收到這個數據後,並不知道交給那個進程,因此內核就會告知對方說本地無人和他通訊,事實上任何一個進程真正可以被動打開模式進行通訊,要向內核註冊使用某一個端口,這個過程稱爲綁定 bind(),綁定在某個端口上。綁定是不能被重複綁定的,就像ssh的實現有兩種一種是openssh,一種是dropbear,若是啓動了openssh服務,他已經綁定在tcp的22號端口上了,若是用dropbear再綁定一樣的22號端口,那麼之後有人向內核發請求和22號通訊時,就不知道和誰通訊了。因此內核絕對不容許兩個進程綁定在同一個端口上。

套接字在本質上是一個設備,兩個主機之間爲了創建通訊,事實上也須要藉助於相似設備的方式來進行完成,意味着這個設備可以讓本地進程跟這個設備關聯起來從而實現跟另一個主機上的設備對應的進程進行通訊。這個設備稱爲套接字,用來代表本地的哪個進程,用來代表了遠程主機上的哪個進程。把本地設備和另一個主機上的設備和遠程設備創建起來對應的關聯關係,就相似於把本地的一個進程跟tty關聯起來了,一個在tty上啓動的進程,若是tty終止了,那麼進程也必定會終止的。若是不想讓tty終止時候,進程必定被中止,則把進程送到後臺執行,並且要使用nohup方式來實現,這裏也是一樣的道理,若是說設備關閉了,那麼應用層進程也沒法通訊了,那事實上這個設備的表現方式就是ip+端口。

clip_image006

由此服務器端本身一個應用進程綁定在這個設備上,也即這個進程註冊使用了這個ip+Port,由此其餘進程就不能再使用了,由此內核接收過來一個報文若是是跟本地的某個ip上某個協議的好比tcp的22號端口來通訊時,就直接關聯到這個進程上來,內核從而知道這是應用程序的哪個進程須要使用此設備或者此套接字進行通訊。可是客戶端如何創建通訊?服務器端是被動打開的,並且綁定在這個套接字上,隨時等待客戶端的請求,客戶端其實不請求時,他是否須要打開一個套接字?是無需打開一個套接字的。由此當某個客戶端須要和服務器端通訊時,他須要如何作?客戶端進程是臨時啓動起來的,啓動起來後,發現要和另一個主機上的套接字通訊,他本地也是要使用一個端口的,由於服務器端數據報文須要迴應過來的,他迴應過來時,有不少進程,迴應過來後,客戶端沒有使用端口,那就不知道迴應給誰了。因此通常而言客戶端進程是臨時啓動的,端口也是臨時註冊使用的。

IANA:進行分配的 IANA(The Internet Assigned Numbers Authority,互聯網數

字分配機構)是負責協調一些使Internet正常運做的機構。同時,因爲Internet已

經成爲一個全球範圍的不受集權控制的全球網絡,爲了使網絡在全球範圍內協調,

存在對互聯網一些關鍵的部分達成技術共識的須要,而這就是IANA的任務。

端口分類:

有些端口是衆所周知的,是固定給某些進程使用的,只能由他們使用。

爲0~1023的端口:管理員纔有權限使用,永久地分配給某應用使用;這些端口普通用戶是沒有權限使用的,主要爲了不某些用戶經過惡意的應用程序來欺騙其餘主要用戶來訪問本機的。是IANA分配的,這裏是嚴格分配的

註冊端口:

1024~41951:也是由IANA分配的,不是永久分配的,稱爲註冊端口。只有一部分被註冊,分配原則上非特別嚴格;

動態端口或私有端口:

41952+: -65535 是本地的客戶端程序看成客戶端時他們臨時使用跟其餘主機進行通訊的端口。

對於有寫很是繁忙的服務器,爲了實現創建鏈接套接字,僅有這麼多端口是不夠用的,若是不夠用時,能夠調整本地的這個範圍,41952並是不固定的,從20000開始後都做爲私有端口也是能夠的,須要修改本地的內核參數來實現

/proc/sys/net/ipv4/ip_local_port_range: 定義了那個範圍內的端口能夠做爲臨時使用的,定義兩個數字,表示能夠作爲臨時端口的起始數字和結束數字,在很是繁忙的服務器須要大量鏈接套接字的狀況下可能須要調整

應用層應用並不是只使用tcp或者是udp,傳輸層協議實現的協議並不是只有TCP、UDP。

傳輸層協議:TCP【傳輸控制協議】、UDP【用戶數據報協議】、SCTP(流控制傳輸協議 對tcp的改進)、DCCP(數據報傳輸控制協議 對udp的改進)

互聯網上95%都是用的tcp協議,由於tcp可靠,stcp可能比tcp有着強大的控制功能,有着更好的消息邊界功能,dccp一樣比udp有着更好的功能。

有些應用層協議能夠徹底不使用tcp也不使用udp或者不使用傳輸層協議,而是直接使用ip報文,這些應用層協議本身直接到達ip報文,這些套接字稱爲 裸套接字【raw socket】

根據套接字關聯到哪種協議上,能夠將套接字分爲三種、

套接字類型:

tcp socket tcp套接字,藉助於tcp進行傳輸

udp socket udp套接字,藉助於udp進行傳輸

raw socket 原始套接字,不使用任何傳輸層協議,而是本身直接封裝全部的控制機制,由IPv4或者IPv6封裝成ip報文後就進行傳輸了。

可是udp socket、raw socket這些套接字並不常見,常常接觸的是tcp socket。

tcp socket如何實現完成數據傳輸的?

互聯網上兩個節點之間進行通訊時,他們要基於tcp完成衆多的功能,

TCP協議的功能包括:

1.鏈接創建

tcp須要三次握手創建鏈接的,須要在傳輸的兩個端點或者兩個主機的進程之間創建通訊會話,稱爲鏈接創建

2.將數據打包成段

打包成段之後,才能藉助ip功能,一段一段進行傳輸,ip報文最多傳輸大小是65535,ip報文最大長度是65535【16位的】,可是ip報文真正在網絡上進行傳輸時,要藉助於設備的傳輸機制,而以太網傳輸的MTU最大協議傳輸單元爲1500字節,因此ip報文是不可能傳輸65535這麼大的報文的,一般都是1500如下。每一段都包含一個校驗和,從而可以實現將報文傳輸到目的端後,目的端能夠檢查這個報文中是否發生了錯誤,從而能夠檢測出數據報文在發送過程當中是否出現錯誤的機制,若是出現了錯誤,讓發送端重傳此報文。

3.確認、重傳以及超時

通常而言tcp是有鏈接的協議,因此發送端發一個報文,接收端就會確認一個報文,從而使得發送端能夠繼續發送後續的報文,若是報文出錯了,能夠重傳,若是發送方發出報文後,接收方老是沒有數據接收到,也須要重傳,須要創建超時機制,從而使得某些超時的報文還能夠重傳。將一個大的數據分隔成段之後,到底哪一段是第一段?哪一段是第二段呢?

4.排序

報文傳輸中須要排序,這些排序中,每個報文都有一個序列號,序列號並不是從0開始的,並且是32位的,其中間是經過某一種算法來生成哪個序列號看成起始序列號的,若是序列號用滿了,一直到達32位最大計數數值了,那麼他還會繞回來,從0開始從新計數,須要注意的是:序列號繞回來後,若是起始值過大的話,可能會致使tcp序列號卷繞,若是傳輸時間過長的話。加序列號的做用:使得tcp分段可以以正確的順序在目的端,在接收方能夠從新組裝起來;接收方能夠確認究竟是哪個報文接收到了,哪個報文沒有接收到,要重傳哪些,接收方也能夠經過序列號來移除重複的段,好比接收一份因爲超時了發送方沒有收到接收方的確認,發送方沒有收到接收方確認,它會再一次的發送過去,本身執行重傳,那麼最終網絡可靠恢復了,即接收方能夠收到兩份,接收到兩份後,會放棄一份重複的報文。

5.流量控制

爲了不網絡上兩臺主機之間處理速率不一樣的主機之間實現通訊時,發送過快的一方把過慢的一方給堵塞淹沒,那麼就須要實現流量控制,要想實現流量控制,tcp協議必需要維護一個緩衝區,因爲tcp通訊時雙向的,那麼其緩存區在任何一端都分爲兩類,一個是發送緩衝,一個是接收緩衝。tcp採用了稱爲滑動窗口的算法來實現向對方通告本身的接收窗口有多大?你能夠一次發多少數據等,因此這個滑動窗口容許包含了總共多少個字節的未確認段同時可以在發送方和接收方之間進行傳輸。若是說按tcp的傳輸機制,發一個報文確認一個報文,那麼tcp效率是不好的,爲了不此狀況,發送方能夠發送一批過去,確認的時候能夠確認一批。那麼這一批是多少呢?確定不能是以發送方爲準、或者以接收方爲準。因此雙方須要經過一個所謂的通知信息來告訴對方互相進行協調一次能夠發多少,從而能夠實現批量發送和傳輸,能夠藉助緩存區和滑動窗口來完成。若是說雙方通訊中的某一方,若是說接收緩衝區滿了,那麼就不能再接收發送緩存區發來的數據了。通知對方說本身的滑動窗口大小爲0,因此不能傳任何數據,若是過了一些時間後,處理數據了,滑動窗口就不爲0了,通知對方滑動窗口有大小了,則對方能夠發送數據過來了。窗口不斷髮生變化,因此稱爲滑動窗口。之因此稱爲滑動的另外一個緣由,接收緩衝區在真正接收數據報文時,假如說其每個數據報文被稱爲一個窗口的話、或者是一個單位的窗口。那麼這個時候當緩存區中接收進來報文後,本地進程須要取出一個處理一個。

clip_image008

假如本地窗口滿了的話,則告訴對方沒有任何空間可接收數據了,可是本地處理事後,就留有空間了,本地窗口向左移動一下,因此左側就留有空間了,這樣依次處理依次往左移,

clip_image010

這就是滑動窗口,藉助於滑動窗口的方式來實現流量控制。

6.擁塞控制

雖然雙方的窗口沒問題,可是當前網絡上面所可以實現通訊的可能不止本進程一個,咱們一個主機上有n個進程都須要於其餘主機進行通訊,兩個主機之間所通訊的進程也不止一個,可是tcp的擁塞控制或者是擁塞避免機制的主要功能就是用來設計防止快速的發送壓垮整個網絡,其跟流量控制是同一個意義,可是從額外來說,他實現了從鏈接創建以後避免網絡被塞滿致使其餘進程通訊沒法進行,而有意設計的一個算法,好比雙方第一次通訊時,發送方並不知道接收方有多少個滑動窗口能夠發送數據,也不知道對方一次能夠處理多少數據,那麼就須要經過試探方式,經過慢啓動的方式,第一次發送時只發送比較小的報文,發送事後很快就處理了,那麼下一次就能夠發送大一些的報文,這樣依次提升。這種機制叫慢啓動的方式,當達到一個量很大時,就須要經過擁塞避免算法來儘量的保證下一次慢速發或者發送的報文小一些。

RFC: 請求註解文檔(Request For Comments) 是一個起草制定協議標準的組織,來定義其實現的細節。

爲了可以實如今兩個主機之間基於tcp的方式創建通訊,在兩個主機的內核之間,其tcp中必須創建可靠的鏈接並進行通訊的,以tcp協議爲例,爲了可以完成通訊雙方須要基於網絡進程通訊,通訊過程是全雙工的

兩個方向各自是獨立的鏈接, 發 收

發送方有一個發送緩衝區,網卡是拿一個發送一個,內核上層應用程序它產生數據的速度比較快,而網卡發送時只能一個一個往外發,因此就經過先把數據放到緩衝區中,有發送緩衝區和接收緩衝區

緩衝區是內核維護的內存空間,通常內核會爲每個進程維護一段緩衝區,準確說應該是兩段 發送緩衝、接收緩衝,其大小能夠定義爲不一樣值。本地的某一個進程要想實現藉助內核通訊,進程須要註冊使用套接字,進程在內核的邊緣註冊使用套接字,進程就經過套接字設備和內核交互,若是內核瞭解到進程是要發送數據,就把數據放到發送緩衝區中,若是是要接收數據,就到接收緩衝區來取數據。一樣對方也是同樣的機制,一個進程進行通訊,要實現雙方通訊,服務器上是使用的監聽套接字,客戶端使用的是臨時套接字。tcp協議就是經過這種方式來進行通訊的。

clip_image012

若是A主機和B主機雙方第一次創建通訊,則先3次握手,握手完成後,發送方開始發送數據,發送方數據放到本地的發送緩衝區中,因而本地的網卡設備從本地的發送緩衝區中取一個數據調製成信號後,發送過去了。對方接收到了,接收到後放到接收緩衝區上,然後內核發現這個是本地套接字通訊的,進而將接收緩衝區中的數據提交給對應的進程。雙方通訊速度隨着網絡帶寬的增長會比較快,而進程處理速度會比較慢,好比:用戶請求的web服務器,訪問一個網頁文件,此網頁文件是在硬盤上放的,須要先到硬盤經過io操做【磁盤io比較慢】上把網頁文件取出,因此一旦發生這種請求時,如接收過來3個請求,而接收緩衝總共能接收10個請求,也即還能夠接收7個請求,此時就要藉助滑動窗口機制來實現。

web通訊就是經過這種模型來實現的,web使用的HTTP協議,而HTTP協議是基於tcp工做的,在大規模的場景中,經過調整或調優主要是調整發送緩衝區大小和接收緩衝區調大等

socket:socket是IPC【進程間通訊】的一種實現,socket主要是跨主機的進程間通訊的方式,它同一或不一樣主機上的進程間進行的通訊,主要實現不一樣主機間的進程進行通訊的。

socket是一種規範,其也有定義的,1983年在4.2版本第一個BSD上第一個完整意義的socket出現,而被接納爲整個Linux或者UNIX上的使用標準。

這一個典型的C/S架構場景中,socket應用程序的使用socket通訊模型以下:

應用程序建立一個socket,socket是一個容許通訊的設備,雙方都要用到,只不過服務器須要將本身的socket綁定在一個衆所周知的端口上,從而可以接收客戶端請求的,另外須要注意的是在通訊中,基於socket通訊的領域,還有另一個概念稱爲domain。不是dns下的domain。

每個socket通訊在domain中實現,domain是識別一個socket的方法(是識別socket地址方法),socket有地址格式。

domain在tcp通訊中,domain有3種

1.Unix Domain: 主要是用於基於socket機制實現同一主機不一樣進程間通訊的一種方式;稱爲AF_UNIX, AF稱爲地址家族,也稱爲地址組,主要用來標記接下來通訊是用於ip地址的IPv4仍是IPv6仍是UNIX domain的方式進行通訊的。因此其地址組名稱也能夠稱爲 AF_UNIX

有些地方posix被稱爲AF_LOCAL,本地的 其地址是一個路徑名(是一個文件)

2.IPv4 Domain: AF_INET, 基於socket機制藉助於ipv4協議實現不一樣主機(也能夠是同一主機)上的進程間通訊的機制; 地址是32位的ipv4地址+16位的端口號(都是經過網絡協議棧來實現的)

MySQL中兩種方式都實現了

3.IPv6 Domain: AF_INET6,基於socket機制藉助於ipv6協議實現不一樣主機(也能夠是同一主機)上的進程間通訊的機制;地址是128位的Ipv6地址+16位的端口號

AF_INET既能實現同一主機上的通訊也能實現不一樣主機上的通訊,那爲何須要用到UNIX domain?UNIX domain和IPv4 domain不一樣之處在於IPv4 domain即使在同一個主機上,他也須要藉助網絡功能來實現,而UNIX domain徹底不經過網絡協議棧,不用封裝網絡ip報文,瞭解到是本機就直接進行通訊。因此本機上兩個進程進行通訊,

若是藉助於IPv4 domain,客戶端發送請求先到內核中,內核須要封裝tcp首部,封裝IP首部,然後路由,路由瞭解到是本機,因此此報文又回來再拆ip首部,再拆tcp首部,再交到本地的另一個進程,那麼此過程浪費了不少效率。

而藉助UNIX domain,他直接在內核中藉助一個文件來實現,在內核中直接建立一個文件,第一個程序發送方往文件中寫數據,接收方往文件中讀數據便可,徹底繞過了網絡協議棧,通訊效率高不少,其可用帶寬Linux內部達幾十G。

所以在同一個主機上,本地既是服務器端又是客戶端時,經過UNIX domain方式進行通訊,效率是高不少的。尤爲像MySQL須要傳輸大量數據的服務器一般都會經過此方式來實現。

不一樣的domain所使用的地址格式是個不相同的,socket既可使用tcp也可使用udp,使用tcp時,表示是面向流的,面向數據流的。而使用udp時,使用的是面向數據報的socket。因此面向流的就有了tcp的特性,能夠實現可靠的雙向的字節流通訊

socket的類型:取決於socket是綁定在tcp仍是udp上,socket也能夠綁定在stcp或者是dccp上。

綁定在TCP上:流式socket,SOCK_STREAM

面向流可實現:可靠、雙向、面向字節流的通訊,沒有消息邊界

綁定在UDP上:數據報式socket, SOCK_DGRAM

是不可靠、有消息邊界

內核將套接字的接口向外提供了,相關的系統調用:

socket(): 建立一個新的socket,被動一方須要將套接字綁定在衆所周知的端口上,意味着其在內核中打開了一個套接字文件

bind():綁定於一個套接字地址上;是上面三種格式中的某一種,綁定只說明瞭須要註冊使用此端口。須要真正接收客戶端鏈接還須要listen。

listen(): 監聽套接字; 一般被動打開那方纔須要listen

accept(): 接收鏈接請求;從內核中接收一個鏈接

客戶端發鏈接請求

connect(): 發起鏈接請求; 主動打開端

鏈接正常後須要發送報文了,

close(): 關閉鏈接

接收和發送鏈接數據 read()和write(): recv(), send(), recvfrom(), sendto()

接收和發送就是向此套接字文件中寫數據和讀數據

真正基於tcp方式進行鏈接通訊時,tcp是一種有狀態的通訊方式

基於TCP客戶端/服務器程序的套接字函數

clip_image014

服務器在進程啓動以前是處於closed狀態的,使用service啓動進程,就打開一個端口等待客戶端請求了,進程就處於監聽狀態了listen,listen以後客戶端就能夠發請求了,客戶端開始時是closed,當其發起connect鏈接請求後,就開始創建tcp的三次握手了,tcp的三次握手當中,首先發送syn,服務器端收到syn後要確認ack和發送syn,然後客戶端要確認ack,然後就發送真正的請求報文了,接着是數據傳輸過程,當傳輸結束後,就調用closed來關閉鏈接,關閉鏈接要4次斷開,而這整個過程大致上tcp協議,他用一種tcp狀態的方式來標記。

tcp協議經過tcp狀態來標記當前處於通訊過程的哪一個階段:

CLOSED, LISTEN, SYN_SENT, SYN_RECV, ESTABLISHED, FIN_WAIT1, CLOSE_WAIT,

FIN_WAIT2, LAST_ACK, TIME_WAIT, CLOSED

從closed到listen稱爲被動打開,listen不監聽了,又轉換成爲closed狀態,客戶端使用connect創建鏈接時,狀態要發生改變了,服務器端接收客戶端請求,服務器是發送客戶端請求,客戶端發送請求稱爲主動打開SYN_SENT,發送syn請求,由closed變爲syn_sent爲主動打開方,因此客戶端從syn_sent到closed,從客戶端發送請求了,對方沒有響應,客戶端發送syn_sent後,服務器端就收到syn_sent請求了,當服務器端收到syn_sent請求後,服務器端就從listen轉爲syn_recv,此過程叫接收syn併發送syn+ack,本身就成了syn_recv了,客戶端收到服務器端發來的syn+ack就變爲established狀態了,然後就能夠交互了established狀態。要先走的那方須要關閉,就發送fin_wait1,

clip_image016

四次斷開的過程是一方請求,另一方確認,而另一方也須要請求然後確認

開始都處於established狀態,其中一方發送fin,其就處於fin_wait1狀態,等待對方確認,確認後,等待對方發送fin,就處於fin_wait2狀態,一旦收到fin後,確認便可,在確認以前須要等待一會,使其進入此通道,此階段叫time_wait。另一端,在接收到fin並執行確認後,然後本身再發送fin,此階段稱爲closed_wait,等待關閉,發送fin後收到對方確認處於last_ack階段,然後轉換成closed狀態。

clip_image018

若是說有不少處於fin_wait1或者是處於fin_wait2狀態的鏈接,則別的鏈接就進入不了,由於全部可以創建的鏈接數是有限的,此時就須要分析產生此種情況的緣由。

經常使用netstat, ss工具查看此時有多少鏈接,每個鏈接處於整個tcp鏈接狀態的那個階段,從而能夠判斷服務器爲何繁忙,甚至能夠檢測服務器上是否有一些非正常鏈接處於在線狀態的。

tcp協議經過tcp狀態來標記當前處於通訊過程的哪一個階段:

CLOSED, LISTEN, SYN_SENT, SYN_RECV, ESTABLISHED, FIN_WAIT1, CLOSE_WAIT,

FIN_WAIT2, LAST_ACK, TIME_WAIT, CLOSED

相關文章
相關標籤/搜索