C# Socket網絡編程(三)

目錄

Socket/TCP

TCP報文格式

TCP三次握手

四次揮手

三次握手和四次揮手面試問題

Socket編程

Socket編程方式

數據傳輸方式

服務器編寫步驟

客戶端編寫步驟


Socket/TCP

TCP報文格式

TCP是一種協議

報文:報紙文字

TCP報文是發送網絡消息需要按照這種報文的格式去包裝數據

例如:

TCP規定的數據包格式:

親愛的[xxx],你好,[XXXXX],保重勿念![xxxx]年[xx]月[xx]日。

那麼按照TCP發送一句話:“I Love You”,則這句話必須按照上面的協議類型包裝

親愛的[小明],你好,[I Love You],保重勿念![2020]年[03]月[27]日。

 

一般需要了解一下幾個字段:

  1. 序號:Seq序號,佔32位,用來表示從TCP源端向目的端發送的字節流,發起方發送數據時對此進行標識

  2. 確認序號:ACK序號,佔32位,只有ACK標誌位爲1時,確認序號字段纔有效,ACK=Seq+1

  3. 標誌位共六個:URG、ACK、PSH、RST、SYN、FIN含義:

    1. URG:緊急指針

    2. ACK:確認序號有效

    3. PSH:接收方應該儘快將這個報文交給應用層

    4. RST:充值連接

    5. SYN:發起一個新連接

    6. FIN:釋放一個連接

  4. 需要注意的是:

    (A)不要將確認序號Ack與標誌位中的ACK搞混了。 (B)確認方Ack=發起方Req+1,兩端配對

TCP三次握手

所謂三次握手(Three-Way Handshake)即建立TCP連接,就是指建立一個TCP連接時,需要客戶端和服務端總共發送3個包以確認連接的建立。在socket編程中,這一過程由客戶端執行connect來觸發,整個流程如下圖所示:

第一次握手:Client將標誌位SYN置爲1,隨機產生一個值seq=J,並將該數據包發送給Server,Client進入SYN_SEND狀態,等待Server確認。

第二次握手:Server收到數據包後由標誌位SYN=1知道Client請求建立連接,Server將標誌位SYN和ACK都置爲1,ACK=J+1,隨機產生一個seq=K,並將該數據包發送給Client以確認連接請求,Server進入SYN_RECV狀態。

第三次握手:Client收到確認後,檢查ACK是否爲J+1,ACK是否爲1,如果正確則將標誌位ACK置爲1,ACK=K+1,並將數據包發送給Server,Server檢查ACK是否爲K+1,如果正確則連接建立成功,Client和Server進入ESTABLISHED狀態,完成三次握手,隨後Client與Server之間就可以開始傳輸數據了。

SYN攻擊:在三次握手過程中,Server發送SYN-ACK後,收到Client的ACK之前的TCP連接稱爲半連接,此時Serve處於SYN_RECV狀態,當收到ACK後,Server轉入ESTABLISHED狀態。SYN攻擊就是Client在短時間內僞造大量不存在的IP地址,並向Server不斷的發送SYN包,Server回覆確認包,並等待Client的確認,由於源地址不存在,因此Server需要不斷重發直至超時,這些僞造的SYN包將長時間佔用未連接隊列,導致正常的SYN請求因爲隊列滿而被丟棄,從而引起網絡阻塞甚至系統癱瘓。SYN攻擊就是一種典型的DDOS攻擊,檢測SYN攻擊方式也很簡單,即當有大量半連接狀態且源地址是隨機的,則可以斷定遭到SYN攻擊了,使用如下命令讓其無處可逃:netstat -nap|grep SYN_RECV

四次揮手

所謂四次揮手即終止TCP連接,就是指斷開一個TCP連接時,需要客戶端和服務端總髮送三個包以確認連接的斷開。在Socket編程中,這一過程由客戶端或服務端任一方執行close來觸發,流程如下:

由於TCP連接是全雙工的,因此每個方向都必須要單獨進行關閉,這一原則是當一方完成數據發送任務後,發送一個FIN來終止這一方向的連接,收到一個FIN只是意味着這一方向上沒有數據流動了,即不會再收到數據了,但是在這個TCP連接上仍然能夠發送數據,直到這一方向也發送了FIN。首先進行關閉的一方將執行主動關閉,而另一方則執行被動關閉。

(1)第一次揮手:Client發送一個FIN,用來關閉Client到Server的數據傳輸,Client進入FIN_WAIT_1狀態。

(2)第二次揮手:Server收到FIN後,發送一個ACK給Client,確認序號爲收到序號+1(與SYN相同,一個FIN佔用一個序號),Server進入CLOSE_WAIT狀態

(3)第三次揮手:Server發送一個FIN,用來關閉Server到Client的數據傳輸,Server進入LAST_ACK狀態

(4)第四次揮手:Client收到FIN後,Client進入TIME_WAIT狀態,接着發送一個ACK給Server,確認序號爲收到序號+1,Server進入CLOSED狀態,完成四次揮手

三次握手和四次揮手面試問題

(1)爲什麼建立連接協議是三次握手,而關閉連接卻是四次握手呢?

這是因爲Server在LISTEN狀態下,當收到建立連接請求的SYN報文後,把ACK和SYN放在一個報文裏發送給客戶端。而關閉連接時,當收到對方的FIN報文時,僅僅表示對方不在發送數據了但是還能接受數據,己方也未必全部數據都發送給對方,所以己方可以立即close,也可以發送一些數據給對方後,再發送FIN報文給對方表示同意現在關閉連接,因此己方ACK和FIN一般都會分開發送。

(2)爲什麼TIME_WAIT狀態還需要等2MSL後才能返回到CLOSED狀態?

這是因爲雖然雙方都同意關閉連接了,而且握手的四個報文也都協調和發送完畢,按理可以直接回到CLOSED狀態(就好比從SYN_SEND狀態到ESTABLISHED狀態那樣),但是因爲我們必須要假想網絡是不可靠的,你無法保證你最後發送的ACK報文會一定被對方收到,因此對方處於LAST_WAIT狀態下的Socket可能會因爲超時未收到ACK報文而重發FIN報文,所以這個TIME_WAIT狀態的作用就是用來重發可能丟失的ACK報文。

Socket編程

Socket編程方式

Socket起源於Unix,而Unix/Linux基本哲學之一就是“一切皆文件”,都可以用“打開Open->讀寫write/read->關閉close”模式來操作文件。Socket就是該模式的一個實現,Socket即是一種特殊的文件,一些Socket函數就是對其進行操作(讀寫IO、打開、關閉)。因此Socket也提供了類似於連接Connect、關閉連接Close、發送、接收等方法的調用

數據傳輸方式

常用stream和dgram

  1. STREAM表示面向連接的數據傳輸方式,數據可以準確無誤地到達另一臺計算機,如果丟失或損壞,可以重新發送,但是相對效率低

  2. DGRAM表示無連接的數據傳輸方式,計算機只管數據傳輸,不做數據校驗,DGRAM所做的校驗工作少,所以效率比STREAM高

QQ視頻聊天和語音聊天使用的就是DGRAM傳輸數據,因爲首先需要保證通信的效率,儘量減少延遲,而數據的正確性是次要的,即使丟失很小的一部分數據視頻和音頻也可以正常解析,最多出現噪點或雜音,不會對通信質量有實質影響

服務器編寫步驟

  1. 調用socket()函數創建一個用於通信的套接字

    買了個手機

  2. 給已經創建的套接字綁定一個端口號,一般通過設置網絡套接口地址和調用bind()函數來實現

    辦張手機卡,插上手機卡

  3. 調用listen()函數使套接字成爲一個監聽套接字

    等待來電

  4. 調用accept()函數來接受客戶端的連接,這時就可以和客戶端通信

    接聽到了打來的電話

  5. 處理客戶端的連接請求

    接通電話聽、說溝通

  6. 終止連接

    掛斷電話

客戶端編寫步驟

  1. 調用socket()函數創建一個用於通信的套接字

    買了個手機

  2. 通過設置套接字地址結構,說明客戶端與之通信的服務器的IP地址和端口號

    輸入對方手機號

  3. 調用Connect()函數來建立與服務器的連接

    撥號,並等接聽

  4. 調用讀寫函數發送或接收數據

    說話、聽話

  5. 終止連接

    掛斷電話

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章