socket 编程
理解 TCP 网络通信原理
掌握
TcpListener服务端与TcpClient客户端开发实现简单的双向通信程序
核心讲解
(1)TCP 通信基础
面向连接,可靠传输,三次握手
服务端:监听端口,等待客户端连接
客户端:主动连接服务端
连接成功后,通过网络流
NetworkStream收发数据
(2)服务端 TcpListener
创建:
new TcpListener(IPAddress.Any, 端口)开始监听:
Start()等待连接:
AcceptTcpClientAsync()阻塞等待获取流:
client.GetStream()
(3)客户端 TcpClient
创建连接:
new TcpClient(IP, 端口)获取流:
GetStream()读写流:
StreamReader、StreamWriter包装
(4)注意点
编码统一,两端一致
粘包问题:TCP 是流协议,数据会粘在一起,需要自己定义协议(长度头、分隔符)
多客户端:服务端每个客户端一个线程 / Task
操作步骤
分别编写服务端和客户端两个项目
先启动服务端,再启动客户端
测试双向收发消息
代码示例
// ===== 服务端 Program.cs =====
using System.Net;
using System.Net.Sockets;
using System.Text;
int port = 8888;
TcpListener listener = new TcpListener(IPAddress.Any, port);
listener.Start();
Console.WriteLine("服务端启动,监听" + port + "端口...");
while (true)
{
TcpClient client = await listener.AcceptTcpClientAsync();
Console.WriteLine("客户端连接:" + client.Client.RemoteEndPoint);
// 每个客户端开一个任务处理
_ = HandleClient(client);
}
async Task HandleClient(TcpClient client)
{
NetworkStream stream = client.GetStream();
StreamReader reader = new StreamReader(stream, Encoding.UTF8);
StreamWriter writer = new StreamWriter(stream, Encoding.UTF8) { AutoFlush = true };
try
{
while (true)
{
string? msg = await reader.ReadLineAsync();
if (msg == null) break;
Console.WriteLine("收到:" + msg);
await writer.WriteLineAsync("收到:" + msg);
}
}
catch
{
Console.WriteLine("客户端断开");
}
finally
{
client.Close();
}
}
// ===== 客户端 Program.cs =====
using System.Net.Sockets;
using System.Text;
string ip = "127.0.0.1";
int port = 8888;
TcpClient client = new TcpClient();
await client.ConnectAsync(ip, port);
Console.WriteLine("已连接服务端");
NetworkStream stream = client.GetStream();
StreamReader reader = new StreamReader(stream, Encoding.UTF8);
StreamWriter writer = new StreamWriter(stream, Encoding.UTF8) { AutoFlush = true };
// 接收线程
_ = Task.Run(async () =>
{
while (true)
{
string? reply = await reader.ReadLineAsync();
if (reply == null) break;
Console.WriteLine("服务端:" + reply);
}
});
// 发送
while (true)
{
string? input = Console.ReadLine();
if (input == "exit") break;
await writer.WriteLineAsync(input);
}
client.Close();
常见误区
忘记 AutoFlush:Writer 缓冲,不 Flush 对方收不到,设置 AutoFlush=true 或者手动 Flush
粘包问题:TCP 是流,没有边界,连续发小数据会粘在一起,要自己定义协议
服务端只能连一个:单线程服务端只能处理一个客户端,要多线程 / 异步
端口占用:端口被占用会报错,换端口或者关闭占用程序
课后练习
编写服务端和客户端,客户端发消息,服务端转大写返回
改造服务端,支持同时多个客户端连接
实现简单的文件传输功能
思考:TCP 和 UDP 的区别是什么?
