計算機網絡再次整理————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 雙向關閉就好。
四次揮手的抓包。
結
介紹網絡的一些周邊之類的,比如域名、網絡地址套接字的一些其他選項。