C#基于TCP通信協(xié)議的實現(xiàn)示例
一、前言
1. 客戶端代碼(TCpClient/Program.cs)
該代碼實現(xiàn)了一個基礎(chǔ)的 TCP 客戶端程序,核心邏輯是與指定 IP 和端口的 TCP 服務(wù)器建立連接,向服務(wù)器發(fā)送控制臺輸入的字符串?dāng)?shù)據(jù),并接收服務(wù)器的響應(yīng)數(shù)據(jù),最后釋放連接資源。核心步驟包括:
- 定義服務(wù)器 IP(
172.16.0.14)和端口(9898); - 通過
TcpClient發(fā)起連接(底層觸發(fā) TCP 三次握手); - 獲取
NetworkStream網(wǎng)絡(luò)流,完成數(shù)據(jù)的發(fā)送與接收; - 異常捕獲與資源釋放(關(guān)閉流和連接,底層觸發(fā) TCP 四次揮手)。
2. 服務(wù)器端代碼(TCPServer/Program.cs)
該代碼實現(xiàn)了一個基礎(chǔ)的 TCP 服務(wù)器程序,核心邏輯是監(jiān)聽指定端口(9898),等待并接收客戶端連接,讀取客戶端發(fā)送的數(shù)據(jù),向客戶端返回響應(yīng),同時保留了另一版監(jiān)聽8888端口的注釋代碼。核心步驟包括:
- 綁定并監(jiān)聽
9898端口; - 阻塞等待客戶端連接(
AcceptTcpClient()); - 獲取
NetworkStream,循環(huán)讀取客戶端數(shù)據(jù)并返回響應(yīng); - 異常捕獲與資源釋放。
二、網(wǎng)絡(luò)編程核心概念與原理
1. 什么是網(wǎng)絡(luò)編程?
網(wǎng)絡(luò)編程是指編寫運行在不同設(shè)備(計算機、嵌入式設(shè)備等)上的程序,通過網(wǎng)絡(luò)協(xié)議實現(xiàn)設(shè)備間的數(shù)據(jù)通信。簡單來說,就是讓兩臺 / 多臺設(shè)備 “對話” 的編程方式。其核心目標(biāo)是跨設(shè)備的數(shù)據(jù)傳輸與交互,依賴 TCP/IP 協(xié)議族等基礎(chǔ)網(wǎng)絡(luò)協(xié)議,TCP 是其中最常用的 “可靠傳輸協(xié)議”。
2. TCP 網(wǎng)絡(luò)編程核心原理
TCP(Transmission Control Protocol,傳輸控制協(xié)議)是一種面向連接、可靠、基于字節(jié)流的傳輸層協(xié)議,也是本次示例代碼的核心依賴:
(1)核心特性
- 面向連接:通信前必須通過 “三次握手” 建立連接,通信結(jié)束通過 “四次揮手” 斷開連接;
- 可靠性:通過序列號、確認(rèn)應(yīng)答、重傳機制保證數(shù)據(jù)不丟失、不重復(fù)、按序到達;
- 字節(jié)流:數(shù)據(jù)以 “字節(jié)” 為單位連續(xù)傳輸,無邊界(需通過緩沖區(qū)和讀取長度判斷數(shù)據(jù)范圍)。
(2)三次握手(建立連接)
類比生活中 “打電話”:
客戶端 → 服務(wù)器:“喂,能聽到嗎?”(SYN 報文,請求建立連接);
服務(wù)器 → 客戶端:“能聽到,你能聽到我嗎?”(SYN+ACK 報文,確認(rèn)請求并反問);
客戶端 → 服務(wù)器:“能聽到,開始溝通吧!”(ACK 報文,連接建立)。
代碼中
new TcpClient(server, port)
是客戶端發(fā)起第一次握手,
AcceptTcpClient()
是服務(wù)器完成三次握手的關(guān)鍵操作。
(3)四次揮手(斷開連接)
類比 “掛電話”:
- 主動方 → 被動方:“我說完了,準(zhǔn)備掛了”(FIN 報文,請求斷開);
- 被動方 → 主動方:“知道你說完了,我確認(rèn)下數(shù)據(jù)”(ACK 報文,確認(rèn)斷開請求);
- 被動方 → 主動方:“我也說完了,你可以掛了”(FIN 報文,告知數(shù)據(jù)發(fā)完);
- 主動方 → 被動方:“好的,掛了”(ACK 報文,斷開連接)。
代碼中
stream.Close()
+
client.Close()
是觸發(fā)四次揮手的核心操作。
三、完整示例代碼(可直接運行)
1. TCP 客戶端完整代碼
using System;
using System.Net.Sockets;
using System.Text;
?
namespace TCpClient
{
internal class Program
{
static void Main(string[] args)
{
// 定義服務(wù)器的IP地址和端口號
string serverIp = "172.16.0.14"; // 替換為實際服務(wù)器IP(本機測試可填127.0.0.1)
int serverPort = 9898;
?
TcpClient tcpClient = null;
NetworkStream networkStream = null;
?
try
{
// 1. 建立TCP連接(底層三次握手)
tcpClient = new TcpClient(serverIp, serverPort);
Console.WriteLine($"成功連接到服務(wù)器 {serverIp}:{serverPort}");
?
// 2. 獲取網(wǎng)絡(luò)流(用于數(shù)據(jù)收發(fā))
networkStream = tcpClient.GetStream();
?
// 3. 發(fā)送數(shù)據(jù)到服務(wù)器
Console.WriteLine("請輸入要發(fā)送的消息:");
string sendMessage = Console.ReadLine();
byte[] sendData = Encoding.UTF8.GetBytes(sendMessage);
networkStream.Write(sendData, 0, sendData.Length);
Console.WriteLine($"客戶端已發(fā)送:{sendMessage}");
?
// 4. 接收服務(wù)器響應(yīng)
byte[] receiveBuffer = new byte[256]; // 定義緩沖區(qū)存儲接收的數(shù)據(jù)
int receiveBytes = networkStream.Read(receiveBuffer, 0, receiveBuffer.Length);
string receiveMessage = Encoding.UTF8.GetString(receiveBuffer, 0, receiveBytes);
Console.WriteLine($"客戶端收到服務(wù)器響應(yīng):{receiveMessage}");
}
catch (Exception ex)
{
Console.WriteLine($"連接/通信異常:{ex.Message}");
}
finally
{
// 5. 釋放資源(底層四次揮手)
if (networkStream != null) networkStream.Close();
if (tcpClient != null) tcpClient.Close();
}
?
Console.WriteLine("客戶端程序結(jié)束,按任意鍵退出...");
Console.ReadKey();
}
}
}2. TCP 服務(wù)器完整代碼
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
?
namespace TCPServer
{
internal class Program
{
static void Main(string[] args)
{
// 定義監(jiān)聽端口
int listenPort = 9898;
TcpListener tcpListener = null;
TcpClient client = null;
NetworkStream networkStream = null;
?
try
{
// 1. 初始化監(jiān)聽器并啟動監(jiān)聽
tcpListener = new TcpListener(IPAddress.Any, listenPort);
tcpListener.Start();
Console.WriteLine($"服務(wù)器已啟動,正在監(jiān)聽端口 {listenPort}...");
?
// 2. 循環(huán)等待客戶端連接(單線程,僅處理一個客戶端)
while (true)
{
// 阻塞等待客戶端連接
client = tcpListener.AcceptTcpClient();
Console.WriteLine("有客戶端成功連接!");
?
// 3. 獲取網(wǎng)絡(luò)流,處理數(shù)據(jù)交互
networkStream = client.GetStream();
byte[] receiveBuffer = new byte[256];
int readBytes;
?
// 循環(huán)讀取客戶端發(fā)送的數(shù)據(jù)(直到客戶端斷開)
while ((readBytes = networkStream.Read(receiveBuffer, 0, receiveBuffer.Length)) != 0)
{
// 解析接收的字節(jié)數(shù)據(jù)為字符串
string receiveMessage = Encoding.UTF8.GetString(receiveBuffer, 0, readBytes);
Console.WriteLine($"服務(wù)器收到客戶端數(shù)據(jù):{receiveMessage}");
?
// 4. 向客戶端發(fā)送響應(yīng)
string responseMessage = "已收到客戶端消息";
byte[] responseData = Encoding.UTF8.GetBytes(responseMessage);
networkStream.Write(responseData, 0, responseData.Length);
Console.WriteLine($"服務(wù)器已發(fā)送響應(yīng):{responseMessage}");
}
}
}
catch (Exception ex)
{
Console.WriteLine($"服務(wù)器異常:{ex.ToString()}");
}
finally
{
// 5. 釋放資源
if (networkStream != null) networkStream.Close();
if (client != null) client.Close();
if (tcpListener != null) tcpListener.Stop();
}
?
Console.WriteLine("服務(wù)器程序結(jié)束,按任意鍵退出...");
Console.ReadKey();
}
}
}四、代碼運行說明
1. 環(huán)境準(zhǔn)備
- 開發(fā)工具:Visual Studio 2019/2022(或其他支持.NET Framework/.NET Core 的 IDE);
- 框架版本:.NET Framework 4.5+ 或 .NET Core 3.1+(代碼兼容)。
2. 運行步驟
先運行TCP 服務(wù)器程序:控制臺輸出 “服務(wù)器已啟動,正在監(jiān)聽端口 9898...”;
再運行
TCP 客戶端程序
- 客戶端控制臺提示 “成功連接到服務(wù)器”;
- 輸入任意字符串(如 “Hello Server!”)并回車;
- 客戶端顯示 “已發(fā)送”,并接收服務(wù)器響應(yīng) “已收到客戶端消息”;
- 服務(wù)器端顯示 “有客戶端成功連接”,并打印收到的 “Hello Server!”,同時提示 “已發(fā)送響應(yīng)”。
五、生活例子理解 TCP 網(wǎng)絡(luò)編程
例子 1:快遞配送(類比 TCP 可靠傳輸)
- 服務(wù)器 = 快遞公司倉庫,客戶端 = 你(收件人);
- 建立連接(三次握手):你下單(SYN)→ 倉庫確認(rèn)接單(SYN+ACK)→ 你確認(rèn)(ACK);
- 數(shù)據(jù)傳輸(可靠):倉庫打包商品(數(shù)據(jù)轉(zhuǎn)字節(jié))→ 快遞員配送(網(wǎng)絡(luò)傳輸)→ 你簽收(確認(rèn)應(yīng)答);若快遞丟失,倉庫重發(fā)(重傳機制);
- 斷開連接(四次揮手):你確認(rèn)收完貨(FIN)→ 倉庫確認(rèn)(ACK)→ 倉庫確認(rèn)無遺漏(FIN)→ 你確認(rèn)(ACK),交易結(jié)束。
例子 2:餐廳點餐(類比客戶端 - 服務(wù)器交互)
- 服務(wù)器 = 餐廳(固定位置,監(jiān)聽 “點餐請求”),客戶端 = 顧客;
- 監(jiān)聽:餐廳開門(啟動
TcpListener),等待顧客; - 建立連接:你走進餐廳(客戶端發(fā)起連接),服務(wù)員接待(
AcceptTcpClient); - 數(shù)據(jù)交互:你說 “要牛肉面”(客戶端發(fā)送數(shù)據(jù))→ 服務(wù)員回復(fù) “好的”(服務(wù)器響應(yīng));
- 斷開連接:你吃完離開(關(guān)閉連接),服務(wù)員結(jié)束服務(wù)(釋放資源)。
六、代碼拓展與注意事項
1. 代碼局限性(進階優(yōu)化方向)
- 單線程服務(wù)器:示例中服務(wù)器只能處理一個客戶端,實際開發(fā)需用多線程 / 異步(如
Task.Run、async/await)支持多客戶端并發(fā); - 無粘包處理:TCP 是字節(jié)流,若客戶端連續(xù)發(fā)數(shù)據(jù),服務(wù)器可能 “粘包”(一次讀取多條數(shù)據(jù)),需自定義協(xié)議(如在數(shù)據(jù)前加長度前綴);
- 硬編碼 IP / 端口:實際項目應(yīng)通過配置文件(如
appsettings.json)讀取,提高靈活性; - 無斷線重連:客戶端斷開后需手動重啟,可增加重連邏輯提升健壯性。
2. 實際應(yīng)用場景
TCP 網(wǎng)絡(luò)編程廣泛用于:
- 即時通訊(微信、QQ 的核心通信);
- 文件傳輸(FTP、網(wǎng)盤上傳下載);
- 數(shù)據(jù)庫連接(MySQL、SQL Server 的客戶端 - 服務(wù)器通信);
- 游戲聯(lián)機(多人游戲的實時數(shù)據(jù)交互)。
七、總結(jié)
本文的示例代碼實現(xiàn)了最基礎(chǔ)的 TCP 客戶端 - 服務(wù)器通信:客戶端發(fā)起連接并發(fā)送字符串,服務(wù)器監(jiān)聽連接、接收數(shù)據(jù)并返回響應(yīng)。背后的核心是 TCP 協(xié)議的 “面向連接、可靠性”,通過三次握手建立連接、四次揮手?jǐn)嚅_連接,借助NetworkStream完成字節(jié)級的數(shù)據(jù)傳輸。
生活中的 “打電話、快遞、點餐” 等例子能幫助理解:網(wǎng)絡(luò)編程本質(zhì)是讓不同設(shè)備按約定規(guī)則 “對話”,而 TCP 是保證這次 “對話” 穩(wěn)定、可靠的 “溝通規(guī)則”。初學(xué)者掌握基礎(chǔ)流程后,可進一步學(xué)習(xí)多線程服務(wù)器、粘包處理、異步 IO 等進階內(nèi)容,實現(xiàn)更貼近實際場景的網(wǎng)絡(luò)程序。
到此這篇關(guān)于C#基于TCP通信協(xié)議的實現(xiàn)示例的文章就介紹到這了,更多相關(guān)C# TCP通信協(xié)議內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
automation服務(wù)器不能創(chuàng)建對象 解決方法
本文主要介紹如何解決“automation服務(wù)器不能創(chuàng)建對象”錯誤,從而解決Visual Studio.Net不能正常使用的問題,需要的朋友可以參考下。2016-06-06
C#實現(xiàn)將Email地址轉(zhuǎn)成圖片顯示的方法
這篇文章主要介紹了C#實現(xiàn)將Email地址轉(zhuǎn)成圖片顯示的方法,涉及C#操作圖片的相關(guān)技巧,需要的朋友可以參考下2015-06-06
C#復(fù)雜XML反序列化為實體對象兩種方式小結(jié)
本文主要介紹了C#復(fù)雜XML反序列化為實體對象兩種方式,主要介紹如何把通過接口獲取到的Xml數(shù)據(jù)轉(zhuǎn)換成(反序列化)我們想要的實體對象,感興趣的可以一起來了解一下2022-04-04
Unity中的PostProcessBuild實用案例深入解析
這篇文章主要為大家介紹了Unity中的PostProcessBuild實用案例深入解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-05-05
Unity Shader實現(xiàn)新手引導(dǎo)遮罩鏤空效果
這篇文章主要為大家詳細介紹了Unity Shader實現(xiàn)新手引導(dǎo)遮罩鏤空效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-02-02
c#使用linq把多列的List轉(zhuǎn)化為只有指定列的List
這篇文章主要介紹了c#使用linq把多列的List轉(zhuǎn)化為只有指定列的List,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12

