首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

揭開 Socket 程式設計的面紗:從 TCP/IP 到實作範例

     編輯:關於C#

前言:網路程式設計的基石

TCP/IP、UDP、Socket 這幾個詞彙幾乎是每位後端開發者的必修課。隨著雲端與微服務普及,理解它們的運作機制比以往更重要。本文將由淺入深,釐清概念、關係,並提供完整的 C# 範例代碼。

一、TCP/IP 與 UDP 是什麼?

  • TCP/IP(Transmission Control Protocol/Internet Protocol)是一套工業標準協定族,專為廣域網(WAN)設計,提供可靠、有序、錯誤檢查的位元組串流傳輸。
  • UDP(User Datagram Protocol)同屬 TCP/IP 協定族,但提供無連線、不可靠的資料報傳輸,適合即時性要求高、容忍丟包的場景(如影音串流、遊戲)。

TCP/IP 協定族分層

圖 1:TCP/IP 協定族包含應用層、傳輸層、網路層、連結層

二、Socket 在哪裡?

Socket 並非協定,而是應用層與 TCP/IP 協定堆疊之間的抽象介面。它隱藏了協定族的複雜細節,讓開發者只需呼叫 socket()、bind()、listen()、accept()、connect()、send()/recv() 等少數 API 即可進行網路通訊。

Socket 位置示意

圖 2:Socket 位於應用層與傳輸層之間,屬於門面模式

三、Socket 通訊流程(以 TCP 為例)

  1. 伺服端:socket() → bind() → listen() → accept()(阻塞等待連線)
  2. 客戶端:socket() → connect()(主動連線)
  3. 連線建立後,雙方透過 send()/recv() 收發資料
  4. 通訊結束,雙方 closesocket()

TCP 連線流程

圖 3:電話撥號類比 — 撥號、接聽、通話、掛斷

四、完整 C# 範例(MFC 風格,易移植至 .NET)

伺服端核心代碼

#define DEFAULT_PORT 2000
void CServerDlg::OnStart()
{
    sockaddr_in local = { AF_INET, htons(DEFAULT_PORT), INADDR_ANY };
    m_Listening = socket(AF_INET, SOCK_STREAM, 0);
    bind(m_Listening, (LPSOCKADDR)&local, sizeof(local));
    listen(m_Listening, 40);
    m_hListenThread = CreateThread(NULL, 0, ListenThread, this, 0, &dwThreadID);
}

DWORD WINAPI CServerDlg::ListenThread(LPVOID lpParam)
{
    CServerDlg* pDlg = (CServerDlg*)lpParam;
    SOCKET Listening = pDlg->m_Listening;
    char szBuf[100];
    while (true) {
        SOCKET ConnectSocket = accept(Listening, (sockaddr*)&ClientAddr, &nLen);
        pDlg->Receive(ConnectSocket, szBuf, 100);
        pDlg->SetRequestText(szBuf);
        strcat(szBuf, " :我是伺服器,收到(");
        strcat(szBuf, inet_ntoa(ClientAddr.sin_addr));
        strcat(szBuf, ")");
        pDlg->Send(ConnectSocket, szBuf, 100);
    }
    return 0;
}

客戶端核心代碼

void CClientDlg::OnSend()
{
    sockaddr_in server = { AF_INET, htons(DEFAULT_PORT), inet_addr(szIP) };
    SOCKET socketTmp = socket(AF_INET, SOCK_STREAM, 0);
    connect(socketTmp, (LPSOCKADDR)&server, sizeof(server));
    Send(socketTmp, szText, 100);
    Receive(socketTmp, szText, 100);
    m_ReplyBtn.SetWindowText(szText);
    closesocket(socketTmp);
}

收發封裝函式(處理黏包/分包)

int Receive(SOCKET fd, char *buf, int len) {
    int cnt = len, rc;
    while (cnt > 0) {
        rc = recv(fd, buf, cnt, 0);
        if (rc == SOCKET_ERROR) return -1;
        if (rc == 0) return len - cnt;
        buf += rc; cnt -= rc;
    }
    return len;
}
int Send(SOCKET fd, char *buf, int len) {
    int cnt = len, rc;
    while (cnt > 0) {
        rc = send(fd, buf, cnt, 0);
        if (rc == SOCKET_ERROR) return -1;
        if (rc == 0) return len - cnt;
        buf += rc; cnt -= rc;
    }
    return len;
}

五、執行畫面

伺服端介面 客戶端介面

圖 4、5:伺服端監聽、客戶端發送/接收介面

結語

Socket 程式設計並不神秘,掌握「連線導向、串流傳輸、阻塞/非阻塞」三大核心概念,配合正確的收發迴圈處理黏包,即可建立穩健的網路應用。建議進一步學習 I/O 多工、非阻塞 I/O、TLS 加密等進階主題。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved