所讀版本:機械工業出版社
這一篇在做什麼
這是整個 Unity 網絡遊戲筆記系列的起點。先把最基本的概念講清楚:
- 什麼是 Socket
- 端口在連接裡扮演什麼角色
- 客戶端與服務端之間的基本通信流程
- 如何用一個最簡單的 Echo 範例把整套流程跑起來
先理解 Socket 是什麼
兩個程序如果要通過網絡交換數據,雙方都需要一個通信端點。這個端點就是 Socket。
一個 Socket 通常包含幾項關鍵信息:
- 使用的通信協議
- 本地主機 IP
- 本地端口
- 遠程主機 IP
- 遠程端口
可以把它理解成一個「帶地址的雙向通道端口」。真正的數據收發,是在這個端點上完成的。
端口的作用
每台設備都可以分配 0~65535 的端口。當兩台機器建立一條 Socket 連接時,本質上就是:
- 本地某個端口
- 經過網絡介質
- 連到遠程某個端口
同一個進程可以持有多個 Socket,因此也可能同時使用多個端口對外通信。
對應到常見的客戶端 / 服務端模型,可以這樣理解:
- 客戶端通常使用不同的本地端口主動發起連接
- 服務端通常固定在某個端口上持續監聽
- 客戶端連入後,服務端才會為這次連接建立對應的通信 Socket

一條 Socket 連接怎麼建立
最基本的 TCP 通信流程可以拆成:
- 客戶端與服務端各自建立 Socket。
- 服務端開始監聽端口。
- 客戶端發起連接,也就是三次握手。
- 服務端接受連接。
- 雙方開始收發數據。
- 任一方關閉連接,也就是四次揮手。

用 Echo 程序跑通最小案例
Echo 程序的目標很簡單:
- 客戶端送出一段文字
- 服務端收到後原樣回傳
- 客戶端再把回應顯示出來
雖然功能極小,但這個例子已經包含了網絡程序最基本的骨架。
客戶端實作
客戶端要做兩件事:
- 建立連接
- 發送請求並接收回應
public class Echo : MonoBehaviour
{
Socket socket;
public TMP_InputField reqField;
public TMP_Text responseText;
public void Connect()
{
//InterNetwork = IPV4
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect("127.0.0.1", 8888); //阻塞
}
public void Send()
{
//Send Req
string sendStr = reqField.text;
byte[] sendBytes = System.Text.Encoding.UTF8.GetBytes(sendStr);
socket.Send(sendBytes); //阻塞
//Receive Rsp
byte[] readBuff = new byte[1024];
int count = socket.Receive(readBuff); //阻塞
string recevieStr = System.Text.Encoding.UTF8.GetString(readBuff, 0, count);
responseText.text = recevieStr;
socket.Close();
}
}
這裡有幾個重要參數:
AddressFamily
用來指定地址族,常見的有:
InterNetwork:IPv4InterNetworkV6:IPv6
SocketType
用來指定 Socket 類型,這裡最常見的是兩種:
Dgram
- 使用 UDP
- 不基於連接
- 可以和多個主機通信
- 不保證可靠送達
Stream
- 使用 TCP
- 基於連接
- 通常對應單一主機連接
- 有可靠傳輸保證
ProtocolType
用來指定底層協議,例如:
TcpUdpRaw
這個範例選的是 Stream + Tcp,也就是最常見的 TCP 流式連接。
服務端實作
服務端的工作順序通常是:
- 建立 Socket
- 綁定 IP 與端口
- 開始監聽
- 接受客戶端連接
- 接收數據並回傳
using System.Net;
using System.Net.Sockets;
//Create Socket
Socket listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//Bind
IPAddress ipAdr = IPAddress.Parse("127.0.0.1");
IPEndPoint ipEp = new IPEndPoint(ipAdr, 8888); //綁定IP和端口
listenSocket.Bind(ipEp);
//Listen
listenSocket.Listen(0);
Console.WriteLine("Server Activated");
while (true)
{
//Accept Client Connection
Socket connectSocket = listenSocket.Accept(); //阻塞
Console.WriteLine("Server Accept Connection");
//Receive
byte[] readBuff = new byte[1024];
int count = connectSocket.Receive(readBuff);
string readStr = System.Text.Encoding.UTF8.GetString(readBuff, 0, count);
Console.WriteLine("Server Receive: " + readStr);
//Send Rsp
byte[] sendBytes = System.Text.Encoding.UTF8.GetBytes(readStr);
connectSocket.Send(sendBytes);
}
服務端幾個關鍵步驟
Bind
Bind 的作用是把 Socket 綁到指定的 IP 與端口上。綁定後,這個 Socket 才知道自己要在哪個地址對外提供服務。
Listen
Listen 表示開始監聽。從這一步開始,服務端會等待外部客戶端連入。
Accept
Accept 用來接受客戶端的連接。這個方法是阻塞的,也就是在真的有客戶端連進來之前,它會一直卡在那裡等待。
IPAddress 與 IPEndPoint
IPAddress:表示 IP 地址IPEndPoint:把 IP 與端口組合成完整的網絡端點
這個 Echo 例子真正教會了什麼
雖然整個程序很短,但它已經完整展示了最基礎的 TCP 編程模型:
- 客戶端主動連接
- 服務端被動監聽
- 雙方都用字節流發送與接收數據
- 同步
Connect、Send、Receive、Accept都可能阻塞
這也為後面幾篇的異步、消息隊列、粘包半包問題打下了基礎。
這一篇先記住的重點
如果只先記最核心的東西,可以收斂成下面幾句:
- Socket 是網絡通信的端點
- TCP 連接依賴 IP + 端口建立
- 服務端先
Bind、再Listen、最後Accept - 客戶端通常主動
Connect Send與Receive處理的都是字節數據- 最簡單的 Echo 程序,已經足夠展示完整的最小通信流程