【計算機網路筆記】2.7 Socket Programming: Creating Network Applications
【計算機網路筆記】2.7 Socket Programming: Creating Network Applications
Hello Guys, I’m LukeTseng. 歡迎你也感謝你點入本篇文章,本系列主要讀本為《Computer Networking: A Top-Down Approach, 8th Edition》,就是計算機網路的聖經,會製作該系列也主要因為修課上會用到。若你喜歡本系列或本文,不妨動動你的手指,為這篇文章按下一顆愛心吧,或是追蹤我的個人公開頁也 Ok。
複習:什麼是 Socket?
簡單來說,Socket(插座)就是應用程式(Application)與網路(Network)之間的介面(Interface)。
Socket 的存在是為了把「網路層只做到主機對主機」提升成「傳輸層要做到行程(process)對行程」的溝通,並讓同一台主機上的許多應用程式能同時共用 TCP/UDP 而不互相搞混。
做比喻的話,行程(process)就像是房子,而 Socket 如同房子中的門。
當使用者想發訊息給別人,使用者會把訊息推出「門」(Socket)外,一旦出門,訊息就交給了「運輸部門」(傳輸層),不用管它是怎麼送的,只要相信它會送到對方的門口。
兩種主要的傳輸選擇:
在建立 Socket 時,身為開發者必須做出一個決定:要用哪種傳輸層協定?
- UDP(User Datagram Protocol):不可靠、無連線。
- TCP(Transmission Control Protocol):可靠、連線導向。
2.7.1 Socket Programming with UDP
UDP 為一種非連線導向(Connectionless)的傳輸協定。
在寫程式時,意即在傳送資料前,不需與對方做握手(Handshaking)協定來建立連線。
運作邏輯:
- 沒有連線:傳送端直接把資料打包,推送到網路中。
- 明確地址:因為沒有預先建立的通道,所以每個資料(Packet/Segment)在送出時,都必須明確附上目的地的 IP 位址 與埠號(Port Number)。
- 不保證送達:如同寄平信,寄出後就管不了,網路會盡力送,但可能會遺失或亂序。
UDP 適用情境:適合對速度要求高、能容忍少量資料遺失的應用,例如 DNS 查詢、語音串流或即時遊戲。
術語解析
- 資料包(Datagram):在 UDP 程式設計中,傳送的獨立資料單元通常被稱為 Datagram。
- 埠號(Port Number):用來識別主機上的特定行程(Process)。
- Server Port:通常固定(如 HTTP 是 80,接下來的範例用 12000),好讓大家找得到。
- Client Port:通常由作業系統自動分配。
AF_INET:代表我們使用 IPv4 位址家族。SOCK_DGRAM:代表我們使用 Datagram socket,也就是 UDP。
UDP Socket 應用
接下來的範例會做以下這四件事情:
- 客戶端會讀入一行字元(資料),並將該行資料送給伺服端。
- 伺服端接收該資料並將字元轉為大寫。
- 伺服端將修改後的這行資料送給客戶端。
- 客戶端接收修改後的資料,接著印出在螢幕上。

Image Source:Computer Networking: A Top-Down Approach (8th ed., p. 185, Figure 2.27)
客戶端的程式檔案名為 UDPClient.py,伺服端稱為 UDPServer.py。
UDPClient.py:Client 的任務是建立 Socket -> 準備資料與地址 -> 寄出 -> 等待回信。
1 | from socket import * |
程式重點:
- 地址打包:注意
sendto()函式,我們把資料和目的地(serverName, serverPort)一起包進去。作業系統會自動把客戶端的 IP 和 Port 也附在封包裡作為「寄件人地址」,讓 Server 知道怎麼回信。 - 自動分配 Port:客戶端程式碼沒有寫
bind(),這代表我們不介意作業系統給我們哪個 Port,只要能用就好。
bind() 方法會在伺服端中看到,用於將 Socket 物件綁定到特定的 IP 位址和埠號(Port)。
接下來是 UDPServer.py:Server 的任務是建立 Socket -> 綁定(Bind)特定 Port -> 進入無限迴圈 -> 收到信 -> 處理 -> 依據「寄件人地址」回信。
1 | from socket import * |
程式重點:
- Server 端必須使用
bind(),就像開店要掛招牌、選固定地址一樣,否則 Client 端不知道要把封包寄到哪裡。 recvfrom()回傳的clientAddress非常重要,因為 UDP 沒有連線狀態,Server 唯一知道「是誰寄來」以及「該回給誰」的依據,就是從封包裡拆出來的來源地址。
2.7.2 Socket Programming with TCP
TCP 是連線導向(Connection-Oriented)的協定。
表示 Client 端和 Server 端在交換資料前,必須先進行握手(Handshaking)協定來建立一條邏輯上的連線。
TCP 特點:
- 可靠性:TCP 保證資料無誤、不遺漏、按順序送達。
- 位元組流(Byte Stream):應用程式看到的不是一個個獨立的封包,而是一條連續的資料流(Pipe),Client 端只要把資料丟進管子,TCP 就會負責把它送到另一端。
TCP vs UDP:
- 在 UDP 中,Client 端每次寄信都要寫地址。
- 在 TCP 中,一旦連線建立(電話接通),Client 端只需對著話筒(Socket)說話,不需要每次都喊對方的名字。
術語解析
- 握手(Handshaking):在傳送任何實際資料前,Client 端和 Server 端交換控制封包(TCP 三次交握)來建立連線的過程,由作業系統在背後完成。
- 歡迎 Socket(Welcoming Socket):Server 端最初建立的 Socket,就像公司的總機櫃檯,它只負責做接待歡迎,任意主機上執行的客戶端行程所發出的初始聯繫,但不負責具體的對話服務。
- 連線 Socket(Connection Socket):當總機接到電話後,會轉接給一位專員,這個專員(新的 Socket)專門負責服務這一位特定的客戶。Server 端會為每一個連上的 Client 端建立一個專屬的連線 Socket。
如下圖,可見 TCP Server 行程會有兩個 sockets。

Image Source:Computer Networking: A Top-Down Approach (8th ed., p. 191, Figure 2.28)
TCP Socket 應用
繼續延續大小寫轉換的例子,下圖是 TCP Socket 的應用程式流程圖:

Image Source:Computer Networking: A Top-Down Approach (8th ed., p. 192, Figure 2.29)
TCPClient.py:Client 的任務是建立 Socket -> 發起連線 -> 傳送資料 -> 接收回應 -> 關閉連線。
1 | from socket import * |
程式重點:
clientSocket.connect()是 TCP 獨有的步驟,執行完這行,Client 和 Server 之間就建立了一條虛擬管道。- 隱含的地址:注意
send()函式不需要參數(serverName, serverPort),因為 Socket 已經記住連線對象是誰了。
TCPServer.py:Server 的任務比較複雜,它需要兩個 Socket:
- Server Socket(門鈴/總機):永遠開著,等待敲門。
- Connection Socket(專員/分機):有人敲門後動態產生,服務完就銷毀。
1 | from socket import * |
程式重點:
serverSocket.accept()是一個會阻塞(Block)的指令,程式跑到這裡會停下來,直到有 Client 連上來為止。一旦有連線,它會生出一個新的 connectionSocket。- 為什麼要兩個 Socket?為了並行性(Concurrency),如果只有一個 Socket,當 Server 正在跟 Client A 傳輸大檔案時,Client B 就連不進來了。透過這種機制,serverSocket 可以持續在門口接客,而將實際的服務工作交給多個 connectionSocket 去做平行處理(雖此例為單執行緒,但實務上會配合多執行緒(Multithreading)使用)。
TCP 與 UDP Socket 程式設計差異對照表
| 比較項目 | UDP Socket | TCP Socket |
|---|---|---|
| 連線建立 | 無連線(Connectionless) | 需要 connect() 和 accept() |
| 傳送指令 | sendto(data, address) | send(data)(地址已隱含) |
| 接收指令 | recvfrom()(需接收來源地址) | recv()(位元組流) |
| Server 架構 | 單一 Socket 處理所有封包 | 歡迎 Socket + 多個 連線 Socket |
| 資料邊界 | 保留(傳送幾次就接收幾次) | 不保留(資料流可能需要多次使用 recv()) |
總整理
複習
- Socket(插座):
- 定義:應用程式(Application)與網路(Network)之間的介面,亦為應用層與傳輸層間的介面。
- 功能:將「主機對主機」的傳輸提升為「行程(Process)對行程」。
- 比喻:Process 是房子,Socket 是門,訊息推出門後,由傳輸層負責運送。
- 開發者的傳輸層協定選擇:
- UDP:不可靠、無連線、速度快。
- TCP:可靠、連線導向。
UDP Socket Programming
UDP 特點:非連線導向(Connectionless)、無握手協定、需明確指定地址、不保證送達。
socket 建立關鍵參數:
AF_INET:IPv4。SOCK_DGRAM:Datagram(代表 UDP)。
運作流程:
| 角色 | 流程與關鍵函式 | 備註 |
|---|---|---|
| Client | 1. socket() 建立2. sendto(data, (ip, port)) 傳送3. recvfrom(bufsize) 接收4. close() 關閉連線 | 無需 bind() 綁定 Port(作業系統會自動分配 Port),傳送時必須打包「目的地地址」。 |
| Server | 1. socket() 建立2. bind('', port) 綁定 Port3. while True: 迴圈監聽4. recvfrom() 接收5. sendto() 回傳 | 必須 bind() 做綁定(固定 Port 別人才找得到)。recvfrom() 回傳 (data, clientAddress),回信時需使用該地址。 |
TCP Socket Programming
TCP 特點:連線導向(Connection-Oriented)、需做握手協定(Handshaking)、可靠傳輸、位元組流(Byte Stream)。
socket 建立關鍵參數:
AF_INET:IPv4。SOCK_STREAM:Stream(TCP)。
TCP 核心機制:雙 Socket 架構
Server 端會有兩種 Socket,以處理並行性 (Concurrency):
- Welcome Socket(歡迎 Socket):如同總機櫃檯,只負責 listen(監聽) 和 accept(接受連線),永遠開啟的通道。
- Connection Socket(連線 Socket):如同專屬專員,accept 接受連線後動態產生,只服務特定 Client,服務完即銷毀。
運作流程:
| 角色 | 流程與關鍵函式 | 備註 |
|---|---|---|
| Client | 1. socket() 建立2. connect((ip, port)) 連線3. send(data) 傳送4. recv() 接收5. close() 關閉連線 | connect() 會觸發三次交握。send()/recv() 不需指定地址(因為連線已建立)。 |
| Server | 1. socket() 建立(此為 Welcome Socket)2. bind() 綁定 Port3. listen(n) 開始監聽4. while True: 無窮迴圈5. accept() 接受連線6.(產生 Connection Socket)處理資料 7. close() 關閉專屬連線 | accept() 會阻塞(block)直到有連線,並回傳 (newSocket, addr)。收發資料是用新產生的 Socket 來做。 |
UDP vs TCP Socket Programming
| 比較項目 | UDP Socket | TCP Socket |
|---|---|---|
| 連線建立 | 無連線(Connectionless) | 需要 connect() 和 accept() |
| 傳送指令 | sendto(data, address) | send(data)(地址已隱含) |
| 接收指令 | recvfrom()(需接收來源地址) | recv()(位元組流) |
| Server 架構 | 單一 Socket 處理所有封包 | 歡迎 Socket + 多個 連線 Socket |
| 資料邊界 | 保留(傳送幾次就接收幾次) | 不保留(資料流可能需要多次使用 recv()) |
