iT邦幫忙

2026 iThome 鐵人賽

DAY 10
0

昨天,我用 Console.ReadLine() 做了一個很簡單的實驗。

我第一次真正理解到,程式「還活著」,不代表 CPU 必須一直空轉。

程式也可以停在某個地方,等待外部事件發生。

在 Console 程式裡,等待的是:

鍵盤輸入

但 Web Server 當然不可能靠Console.ReadLine(),來等 Browser。

所以新的問題就出現了:

Web Server 到底在等什麼?

Browser 的 Request 又是怎麼真正進入我的 C# 程式?

今天,我第一次讓自己的 Mini Web Framework 專案真正碰到網路。


如果 Web Server 要等待 Client,那它到底是在等待什麼?

以前聽到:

Server 正在監聽 Port 5000。

我其實只是把這句話背起來。

像 ASP.NET Core 常看到:

localhost:5000

我知道 5000 是 Port。

也知道 Browser 可以連進去。

但如果真的要我回答:

「你的 C# 程式到底怎麼知道有人連到 Port 5000?」

我其實回答不出來。

所以今天我不想直接使用 ASP.NET Core,我想先從最基本的 TCP Server 開始。

我先建立:

var listener = new TcpListener(IPAddress.Loopback, 5000);

接著啟動:

listener.Start();

並印出:

Console.WriteLine("Server 已啟動,正在等待連線...");

接著最重要的是:

TcpClient client = listener.AcceptTcpClient();

執行後,我看到:

Server 已啟動,正在等待連線...

然後程式就停在那裡。

一開始我差點以為程式卡住了。

但仔細想想,這其實正是我想要的結果。

因為:

AcceptTcpClient();

現在正在等待 Client 建立 TCP 連線。

這讓我第一次把昨天的概念接到網路:

Day9

Console.ReadLine()

等待鍵盤輸入

今天變成:

Day10

AcceptTcpClient()

等待網路 Client

https://ithelp.ithome.com.tw/upload/images/20260811/20183395nYE5pSLrxx.png

IP 和 Port 到底在做什麼?

今天的 Server 建立在:

IPAddress.Loopback

以及:

Port 5000

Loopback 對應的就是:

127.0.0.1

也就是:

這台電腦自己,所以今天的 Client 和 Server 都在同一台電腦。

可以簡化成:

Client

│ 127.0.0.1:5000

Server

而 Port 可以先理解成一個「入口編號」。

同一台電腦可能同時執行很多網路程式:

127.0.0.1:5000
127.0.0.1:5001
127.0.0.1:8080

Port 讓作業系統知道:

這個網路資料到底要交給哪一個程式。

所以:

IP

找到哪一台電腦

Port

找到這台電腦上的哪個服務


接著,我另外建立 Client 去連:

127.0.0.1:5000

當 Client 成功連線後,原本 Server 的畫面立刻出現:

收到一個連線!

這一刻其實很重要。

因為我第一次親眼看到:

Client

│ 建立 TCP 連線

TcpListener


AcceptTcpClient()


收到一個連線

也就是說,Server 並不是一直「猜」有沒有人來,它可以停在等待連線的狀態,直到真的有 Client 連進來。


接著,我透過:

NetworkStream stream = client.GetStream();

取得網路資料流。

再使用:

int length = stream.Read(buffer, 0, buffer.Length);

讀取 Client 傳來的資料。

這裡又出現了一個有趣的現象。

Server 已經顯示:

收到一個連線!

但程式又停住了。

一開始我以為是不是出錯。

後來才發現:

建立連線和收到資料,其實是兩個不同階段。

流程其實是:

等待 Client

Client 建立連線

AcceptTcpClient() 完成

等待資料

stream.Read()

收到資料

所以:

「有人連進來」

不代表:

「對方已經把資料送過來」

這是今天另一個很重要的發現。

https://ithelp.ithome.com.tw/upload/images/20260811/20183395ZMeEwIA7HP.png

https://ithelp.ithome.com.tw/upload/images/20260811/20183395Rhn6b0tK8e.png

https://ithelp.ithome.com.tw/upload/images/20260811/20183395wUGvoYy8s4.png

https://ithelp.ithome.com.tw/upload/images/20260811/20183395glviJLhVU2.png

Socket 到底是什麼?

做到這裡,我才開始理解 Socket 的角色。

以前看到 Socket,我總覺得它是一個很抽象的網路名詞。

但今天可以先把它理解成:

程式和網路世界溝通的一個端點。

Client 需要一個網路端點。

Server 也需要一個網路端點。

雙方透過 IP、Port 和 TCP 建立連線後,就可以開始交換資料。

可以簡化成:

Client Process

Socket

│ TCP

Socket

Server Process

而今天 C# 提供的:

TcpListener

和:

TcpClient

其實都是幫我們包裝底層 Socket 操作的類別。

所以今天我雖然沒有直接操作最底層的 Socket 類別,但已經第一次真正透過 TCP 建立 Client 與 Server 的連線。


官方怎麼說?

Microsoft 對 TcpListener 的描述,可以簡化理解為:

它提供監聽 TCP 網路 Client 連線的能力。

而:

AcceptTcpClient()

會等待傳入的 TCP 連線,成功後取得一個代表該連線的 TcpClient。

接著:

GetStream()

讓 Server 可以透過 NetworkStream 接收或傳送資料。

所以今天自己做出的流程:

Listen

Accept

GetStream

Read

並不是我自己亂猜出來的流程,而是 TCP Server 實際工作的基本步驟。


昨天的我:

Web Server 可以一直活著,因為它會等待 Request。

今天的我:

Server 並不是直接等待「HTTP Request」這個抽象概念,它更底層會先等待網路連線,取得連線後,再從網路資料流中讀取 Client 傳來的 bytes。

也就是:

Client

建立 TCP 連線

Server Accept

NetworkStream

讀取 bytes

才開始理解資料內容

我以前都是直接從:

HTTP Request 開始學。

今天才第一次知道,在 HTTP 出現以前,下面其實還有 TCP 和 Socket。


今天是 Mini Web Framework 第一次真正具備「網路能力」的一天。

前面的專案本質上都還只是:

Console Application

但今天它已經可以:

啟動

監聽 Port 5000

等待 Client

接受 TCP 連線

讀取 Client 傳來的資料

繼續等待

雖然現在還沒有 Routing、Controller、Middleware,甚至還不懂 HTTP。

但它已經跨過非常重要的一步,它不再只是自己執行自己的程式,而是開始能接收外面的世界傳進來的資料。

這也是從普通程式走向 Web Server 的真正起點。


上一篇
為什麼一般程式執行完就結束,但 Web Server 可以一直等 Request?
下一篇
Browser 傳來的 Request 到底長什麼樣?
系列文
程式設計沒有告訴你的事:30 天破解每一個 Why16
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言