Socket 入坑

什麼是Socket

Socket(套接字)是在計算機網絡中實現通信的一種機制。它提供了一種應用程序編程接口(API),允許應用程序通過網絡進行數據傳輸和通信。

在網絡通信中,Socket 可以被看作是提供網絡連接的一種抽象。它可以用於在不同的計算機上的應用程序之間建立雙向的通信鏈路。通過 Socket,應用程序可以發送和接收數據,與其他應用程序進行實時的、可靠的通信。

Socket 位於傳輸層和應用層之間,負責處理網絡的底層細節。它封裝了底層的網絡協議(如 TCP 或 UDP),提供了一組簡單而有效的函數和方法,使得開發者能夠方便地使用網絡進行通信。
image

Socket通信模型

使用 Socket 進行通信的一般過程如下:

  1. 創建 Socket:應用程序通過調用系統提供的函數或類庫來創建一個 Socket 實例,指定通信協議、地址和端口等參數。
  2. 建立連接:對於客戶端,它會主動發起連接請求,指定服務器的 IP 地址和端口;對於服務器端,它會監聽指定的端口,並在有連接請求時接受連接。
  3. 數據傳輸:連接建立成功後,應用程序可以通過 Socket 發送和接收數據。發送數據時,將數據寫入 Socket 的輸出緩衝區;接收數據時,從 Socket 的輸入緩衝區讀取數據。
  4. 斷開連接:通信完成後,可以通過關閉 Socket 來斷開連接,釋放資源。

Socket 提供了不同的通信協議,最常用的是 TCP(傳輸控制協議)和 UDP(用戶數據報協議)。TCP 提供可靠的連接,並確保數據的有序傳輸;而 UDP 則是一種無連接的協議,只提供數據的不可靠傳輸。

總結來說,Socket 是一種用於在計算機網絡中實現通信的編程接口。它提供了創建連接、發送和接收數據的函數和方法,使得應用程序能夠方便地進行網絡通信。
image

消息緩衝區

Socket 消息緩衝區是指 Socket 對象內部用於存放發送和接收數據的緩衝區。消息緩衝區允許應用程序在發送和接收數據時進行數據的緩存和處理,以提高效率和性能。

對於發送數據,應用程序將要發送的數據寫入到 Socket 的輸出緩衝區中。這些數據並不立即發送到網絡,而是在緩衝區中等待適當的發送時機。例如,當緩衝區滿了或者應用程序調用了發送數據的方法時,緩衝區中的數據會被髮送出去。

對於接收數據,Socket 會將從網絡中接收到的數據存放在輸入緩衝區中,等待應用程序讀取。應用程序可以通過讀取輸入緩衝區中的數據來獲取接收到的消息。如果輸入緩衝區爲空,應用程序可能會阻塞,直到有新的數據到達。

消息緩衝區的大小可以根據需要進行配置。較小的緩衝區可能會導致頻繁的發送和接收操作,而較大的緩衝區可能會增加延遲和內存消耗。因此,在實際應用中,需要根據數據的傳輸量和性能需求來合理地配置消息緩衝區的大小。

需要注意的是,消息緩衝區只是作爲臨時存儲數據的中介,數據的傳輸仍然是通過網絡進行的。Socket API 提供了相應的方法用於操作消息緩衝區,如發送數據、接收數據和清空緩衝區等。

綜上所述,Socket 消息緩衝區是 Socket 對象內部用於存放發送和接收數據的緩衝區,它在數據發送和接收過程中起到緩存和臨時存儲的作用。
image

如何理解“套接字”

在計算機編程中,套接字是用於在網絡上進行數據傳輸的編程接口。每個打開的套接字都會被操作系統分配一個唯一的套接字句柄,也就是 fd。這個句柄可以看作是對打開套接字的引用,通過它可以進行讀取、寫入、關閉等操作。

入門demo

服務端

//1 創建Socket對象
socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

//2 綁定ip和端口
IPAddress ip = IPAddress.Parse("127.0.0.1");
IPEndPoint ipEndPoint = new IPEndPoint(ip, 50001);
socketServer.Bind(ipEndPoint);

//3、開啓偵聽(等待客戶機發出的連接),並設置最大客戶端連接數爲10
socketServer.Listen(10);

//4、【阻塞】,等待客戶端連接
Socket newSocket = socketServer.Accept();

//5、【阻塞】,等待讀取客戶端發送過來的數據
byte[] data = new byte[1024 * 1024];
int readLeng = newSocket.Receive(data, 0, data.Length, SocketFlags.None);

//6、讀取數據
var msg = Encoding.UTF8.GetString(data, 0, readLeng);

客服端

//1 創建Socket對象
socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

//2 連接到服務端
IPAddress ip = IPAddress.Parse("127.0.0.1");
IPEndPoint ipEndPoint = new IPEndPoint(ip, 50001);
socketClient.Connect(ipEndPoint);

//3 發送消息到服務端
socketClient.Send(Encoding.UTF8.GetBytes("hello,word"));

不過,這裏有個很大的問題,服務端只能建立一個客戶端連接和接受一次客戶端發來的消息。如果想要連接更多的客戶端和接受無數次的消息,服務端代碼兩處阻塞的地方需要另外開一個線程然後包到循環裏面去。

修改後的服務端代碼如下:

void .... ()
{
    //1 創建Socket對象
    socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

    //2 綁定ip和端口
    IPAddress ip = IPAddress.Parse("127.0.0.1");
    IPEndPoint ipEndPoint = new IPEndPoint(ip, 50001);
    socketServer.Bind(ipEndPoint);

    //3、開啓偵聽(等待客戶機發出的連接),並設置最大客戶端連接數爲10
    socketServer.Listen(10);

    //開啓新的線程,循環等待新的客戶端連接
    Task.Run(() => { Accept(socketServer); });
}

void Accept(Socket socket)
{
    while (true)
    {
        //4、【阻塞】,等待客戶端連接
        Socket newSocket = socket.Accept();
        //開啓新的線程,循環等待接收新的數據
        Task.Run(() => { Receive(newSocket); });
    }
}

void Receive(Socket newSocket)
{
    while (true)
    {
        //5、【阻塞】,等待讀取客戶端發送過來的數據
        byte[] data = new byte[1024 * 1024];
        int readLeng = newSocket.Receive(data, 0, data.Length, SocketFlags.None);
        //6、讀取數據
        var msg = Encoding.UTF8.GetString(data, 0, readLeng);
    }
}

參考

【農碼一生】
https://www.cnblogs.com/zhaopei/p/Socket1.html

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