Socket 入坑

2023-07-25 06:00:31

什麼是Socket

Socket(通訊端)是在計算機網路中實現通訊的一種機制。它提供了一種應用程式程式設計介面(API),允許應用程式通過網路進行資料傳輸和通訊。

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

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

Socket通訊模型

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

  1. 建立 Socket:應用程式通過呼叫系統提供的函數或類庫來建立一個 Socket 範例,指定通訊協定、地址和埠等引數。
  2. 建立連線:對於使用者端,它會主動發起連線請求,指定伺服器的 IP 地址和埠;對於伺服器端,它會監聽指定的埠,並在有連線請求時接受連線。
  3. 資料傳輸:連線建立成功後,應用程式可以通過 Socket 傳送和接收資料。傳送資料時,將資料寫入 Socket 的輸出緩衝區;接收資料時,從 Socket 的輸入緩衝區讀取資料。
  4. 斷開連線:通訊完成後,可以通過關閉 Socket 來斷開連線,釋放資源。

Socket 提供了不同的通訊協定,最常用的是 TCP(傳輸控制協定)和 UDP(使用者資料包協定)。TCP 提供可靠的連線,並確保資料的有序傳輸;而 UDP 則是一種無連線的協定,只提供資料的不可靠傳輸。

總結來說,Socket 是一種用於在計算機網路中實現通訊的程式設計介面。它提供了建立連線、傳送和接收資料的函數和方法,使得應用程式能夠方便地進行網路通訊。

訊息緩衝區

Socket 訊息緩衝區是指 Socket 物件內部用於存放傳送和接收資料的緩衝區。訊息緩衝區允許應用程式在傳送和接收資料時進行資料的快取和處理,以提高效率和效能。

對於傳送資料,應用程式將要傳送的資料寫入到 Socket 的輸出緩衝區中。這些資料並不立即傳送到網路,而是在緩衝區中等待適當的傳送時機。例如,當緩衝區滿了或者應用程式呼叫了傳送資料的方法時,緩衝區中的資料會被傳送出去。

對於接收資料,Socket 會將從網路中接收到的資料存放在輸入緩衝區中,等待應用程式讀取。應用程式可以通過讀取輸入緩衝區中的資料來獲取接收到的訊息。如果輸入緩衝區為空,應用程式可能會阻塞,直到有新的資料到達。

訊息緩衝區的大小可以根據需要進行設定。較小的緩衝區可能會導致頻繁的傳送和接收操作,而較大的緩衝區可能會增加延遲和記憶體消耗。因此,在實際應用中,需要根據資料的傳輸量和效能需求來合理地設定訊息緩衝區的大小。

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

綜上所述,Socket 訊息緩衝區是 Socket 物件內部用於存放傳送和接收資料的緩衝區,它在資料傳送和接收過程中起到快取和臨時儲存的作用。

如何理解「通訊端」

在計算機程式設計中,通訊端是用於在網路上進行資料傳輸的程式設計介面。每個開啟的通訊端都會被作業系統分配一個唯一的通訊端控制程式碼,也就是 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