計算機網絡再次整理————tcp的關閉[七]

前言

tcp的關閉不是簡單粗暴的,相對而言是友好優雅的,好聚好散吧。

那麼友好的關閉方式是這樣的:

假設這裡是客戶端請求關閉的,服務端倒過來。

客戶端:我要請求關閉
服務端:我接收到你的請求了,等我把要發的數據發完。
服務端:我要發的數據發完了,可以關閉了。
客戶端:好的,我已經執行清理工作了,關閉結束。

那麼這個時候為什麼服務端直接告訴客戶端可以直接關閉了呢?

為什麼服務器端要做一些事情呢,到底有啥用。

回到設計的角度上,理論上是越簡單越好的,遇到了什麼問題,才使得我們要增加一個步驟呢。

那麼就開始介紹到底發送了什麼事情,這要從。。。。

正文

為什麼會有四次揮手呢?

網上有很多故事哈。

下面其中一個故事是:

答:因為當Server端收到Client端的SYN連接請求報文後,可以直接發送SYN+ACK報文。其中ACK報文是用來應答的,SYN報文是用來同步的。但是關閉連接時,當Server端收到FIN報文時,很可能並不會立即關閉SOCKET,所以只能先回復一個ACK報文,告訴Client端,”你發的FIN報文我收到了”。只有等到我Server端所有的報文都發送完了,我才能發送FIN報文,因此不能一起發送。故需要四步握手。

下面自我整理一下。

為什麼要有揮手這個操作呢?

本質上要回到tcp是流的這種操作上。

流有什麼特點呢?就是不知道什麼時候結束。

那麼進行假如客戶端發送數據完畢後,那麼就需要告訴服務端發送完畢了。

服務端也需要告訴客戶端收到了客戶端的信號了,告訴客戶端我已經知道你發送結束了。這就兩次揮手了。

但是tcp其實是一對一的,雙向通信的,你客戶端發送完畢了,服務端不一定數據發送完畢啊。

那麼客戶端應該還在接收消息,tcp應該是半關閉了。

那麼服務端發送數據完畢後,也應該給客戶端一次揮手,告訴客戶端:服務端已經發送完畢了,這就3次揮手了。

客戶端應該也給服務端發送信號,自己收到了服務端結束數據傳輸了,你如果不給服務端傳輸,那麼服務端也不知道你信號收到了。

那麼其實四次揮手也就是因為tcp是流的這個特性了,因為要告訴對方,流結束了,對方也要回應流結束標誌收到了。

具體實現就是下面這個了:

這裡順便說一下為什麼tcp連接要三次握手呢? 這是因為tcp是雙向通信了。

A->B 請求連接,那麼說明A->B 是能夠通信的。

但是B可不一定能到A,因為有防火牆等,那麼B 就要發送信息給 A,既是告訴B能收到B的信息,也是試探一些B是否能發送給A。

那麼A收到B的數據後,那麼也得回應一下啊,不然B也不知道能發送信息到A啊。這就三次握手了。

實驗代碼服務端:

// See //aka.ms/new-console-template for more information

using System.Net;
using System.Net.Sockets;

var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
var ipAddress = IPAddress.Parse("127.0.0.1");
EndPoint endPoint = new IPEndPoint(ipAddress, 8888);
socket.Bind(endPoint);
socket.Listen();
var clientSocket = socket.Accept();
while (true)
{
    Console.WriteLine("開始接收");
    var receiveMessage = new Byte[1000];
    var size = clientSocket.Receive(receiveMessage);
    if (size == 0)
    {
        clientSocket.Close();
        break;
    }
    else
    {
        Console.WriteLine("接收到消息");
        Console.WriteLine("receive message is:"+System.Text.Encoding.UTF8.GetString(receiveMessage));
    }
}

實驗代碼客戶端:

// See //aka.ms/new-console-template for more information

using System.Net;
using System.Net.Sockets;

var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
var ipAddress = IPAddress.Parse("127.0.0.1");
EndPoint endPoint = new IPEndPoint(ipAddress, 8888);
socket.Connect(endPoint);
socket.Send(System.Text.Encoding.UTF8.GetBytes("hello service"));
Console.WriteLine("發送成功");
socket.Shutdown(SocketShutdown.Send);
Console.ReadLine();

上面客戶端調用Shutdown關閉自己的發送端。

因為服務端不發送消息,直接收到客戶端的傳輸完成信號後,直接close 雙向關閉就好。

四次揮手的抓包。

介紹網絡的一些周邊之類的,比如域名、網絡地址套接字的一些其他選項。