一、TCP 基础理论知识点 + 对应代码
1.1 TCP 四大核心特点(背诵知识点)
-
面向连接:通信前三次握手建立连接
-
流式无边界传输:数据连续流传输,需要固定缓冲区接收
-
可靠传输:自带确认重传,无丢包
-
全双工:两端可同时收发数据
1.2 Socket 核心构造参数(知识点 + 对应代码)
知识点:TCP 套接字固定三参数:IPv4地址族、流式套接字、TCP协议
cs
// 对应考点:TCP协议参数固定写法
new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
参数释义:
-
AddressFamily.InterNetwork:使用 IPv4 协议 -
SocketType.Stream:TCP 流式传输 -
ProtocolType.Tcp:指定 TCP 通信协议
二、服务端五步法
- new Socket() 创建服务端监听对象
- Bind() 绑定本机 IP + 端口
- Listen(100) 开启端口监听
- Accept() 阻塞接收客户端连接
- Receive() 循环接收客户端数据
步骤1:创建服务端Socket对象(知识点+代码)
知识点:服务端全局声明Socket对象,用于监听客户端连接
cs
// 服务端核心监听对象
Socket server = null;
步骤2:自动获取本机IPv4地址(知识点+代码)
知识点:自动遍历本机所有网卡,筛选IPv4地址,适配不同电脑
cs
string ipStr = "";
int port = 63323; // 高位端口,避免冲突
// 获取本机所有网络地址
IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName());
foreach (IPAddress item in host.AddressList)
{
// 只保留IPv4
if (item.AddressFamily == AddressFamily.InterNetwork)
{
ipStr = item.ToString();
}
}
步骤3:绑定IP和端口(Bind)(知识点+代码)
知识点:将Socket与本机IP、端口绑定,对外开放服务端口
cs
IPAddress address = IPAddress.Parse(ipStr);
IPEndPoint endPoint = new IPEndPoint(address, port);
server.Bind(endPoint); // 绑定端口核心方法
步骤4:开启端口监听(Listen)(知识点+代码)
知识点:Listen(最大挂起连接数),开启端口监听,等待客户端接入
cs
server.Listen(100); // 允许最多100个排队连接
步骤5:异步监听多客户端连接(Accept)(知识点+代码)
知识点:双层Task嵌套,外层循环接收新客户端,实现多客户端通信
cs
CancellationTokenSource cts;
public void AcceptDataMul()
{
cts = new CancellationTokenSource();
Task.Run(() =>
{
while (!cts.IsCancellationRequested)
{
// 阻塞接收客户端连接
Socket client = server.Accept();
}
}, cts.Token);
}
步骤6:单客户端独立接收数据(知识点+代码)
知识点:每个客户端独立子线程接收数据,互不干扰;修复TCP粘包BUG
cs
// 固定缓冲区,解决TCP流式无边界粘包问题
byte[] buffer = new byte[1024 * 10];
int length = client.Receive(buffer);
if (length <= 0) break; // 客户端离线断开
步骤7:跨线程UI更新(必考知识点+代码)
知识点:子线程禁止直接操作UI,必须使用Invoke回调主线程
cs
string recStr = Encoding.UTF8.GetString(buffer, 0, length);
Invoke(new Action(() =>
{
richTextBox1.AppendText(recStr + Environment.NewLine);
}));
步骤8:客户端断开资源释放(知识点+代码)
知识点:捕获异常,主动关闭套接字,避免端口占用、内存泄漏
cs
catch (Exception)
{
client.Close();
client.Dispose();
break;
}
服务端关键考点
- 自动筛选本机 IPv4 地址,排除 IPv6
- 多客户端原理:双层 Task 外层:循环 Accept 接客户端 内层:每个客户端独立线程收数据
- 跨线程 UI 报错解决 :子线程更新控件必须用
Invoke - TCP 粘包修复 :固定缓冲区
new byte[1024*10] - 线程安全 :
CancellationTokenSource安全终止后台任务
四、客户端四步法
- 创建客户端 Socket
- 指定服务端 IPEndPoint(IP + 端口)
- ConnectAsync 异步连接(不卡死 UI)
- Send() 发送数据
步骤1:声明客户端Socket(知识点+代码)
知识点:单客户端通信,仅需一个Socket对象
cs
Socket client;
步骤2:创建客户端Socket(知识点+代码)
知识点:客户端参数与服务端一致,保证通信协议匹配
cs
client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
步骤3:配置服务端终端节点(知识点+代码)
知识点:客户端必须指定服务端精准IP+端口才能连接
cs
IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse("192.168.219.12"), 63323);
步骤4:异步连接服务端(核心考点+代码)
知识点:ConnectAsync异步连接,不阻塞UI主线程,避免界面卡死
cs
await client.ConnectAsync(endpoint);
步骤5:连接成功UI状态联动(知识点+代码)
知识点:禁止重复连接,按钮状态互斥,优化交互逻辑
cs
label1.Text = "连接成功";
button1.Enabled = false;
button2.Enabled = true;
步骤6:连接失败容错处理(知识点+代码)
知识点:捕获服务端未开启、IP错误、端口错误异常
cs
label1.Text = "连接成功";
button1.Enabled = false;
button2.Enabled = true;
五、客户端发送数据 知识点逐段对应
5.1 连接状态校验(防报错知识点+代码)
知识点:发送数据前必须判断Socket非空、处于连接状态
cs
if (client == null || !client.Connected)
{
MessageBox.Show("还没连接到服务器,请先连接服务器");
return;
}
5.2 空数据校验(规范考点+代码)
知识点:禁止发送空数据,无效通信拦截
cs
if (string.IsNullOrEmpty(textBox1.Text))
{
MessageBox.Show("发送数据不能为空");
return;
}
5.3 UTF8编码转换(乱码解决考点+代码)
知识点:收发统一UTF8编码,彻底解决中文乱码
cs
byte[] data = Encoding.UTF8.GetBytes(textBox1.Text);
client.Send(data);
label1.Text = "发送成功";
5.4 异常完整资源释放(高频考点+代码)
知识点:三段式资源释放:关闭通道→关闭连接→释放资源
cs
if (client != null)
{
if (client.Connected)
client.Shutdown(SocketShutdown.Both); // 关闭读写通道
client.Close(); // 关闭连接
client.Dispose(); // 释放资源
}
// 重置按钮状态
button1.Enabled = true;
button2.Enabled = false;
客户端安全规范
- 发送前判空:
client!=null && client.Connected - 禁止发送空字符串
- 统一 UTF8 编码 防止中文乱码
- 异常三步释放资源:
Shutdown→Close→Dispose
五、高频易错点
5.1 线程安全控制(CancellationToken)
知识点:使用取消令牌安全终止异步线程,杜绝后台线程残留
cs
CancellationTokenSource cts2 = new CancellationTokenSource();
Task.Run(() => {}, cts2.Token);
5.2 修复TCP原生粘包BUG
知识点:废弃 client.Available 动态缓冲区,使用固定缓冲区循环接收
cs
// 正确写法
byte[] buffer = new byte[1024 * 10];
int length = client.Receive(buffer);
// 错误原生写法(已废弃)
// byte[] buffer = new byte[client.Available];
- 禁止子线程直接操作 UI,必须 Invoke
- TCP 无数据边界,禁用 client.Available
- 端口建议高位(>10000)防冲突
- 客户端 IP 必须与服务端本机 IPv4 一致
- 必须异步连接,同步 Connect 会卡死界面
- 通信完毕必须释放资源,否则端口占用、内存泄漏