C# 基于 Socket 实现以太网 TCP 服务器
本文介绍如何在 C# 环境中通过底层 Socket API 搭建一个支持多客户端连接的以太网 TCP 服务器。内容包含从对象声明、IP 端口绑定到开启监听及处理数据收发的核心代码逻辑。
基础引用与类结构
在 C# 项目中实现以太网通信,首先需要引入 System.Net.Sockets 命名空间。该命名空间提供了构建网络应用所需的基类。为了明确代码意图,建议采用具有描述性的变量命名方式:
socketSever:作为服务端的主 Socket 对象,既可用于绑定和监听,也代表整个服务实例。TcpListener:.NET 提供的更高级别的 TCP 监听类,若需简化开发可替代直接使用 Socket。TcpClient:用于表示已连接的客户端实例。
Socket 构造函数与参数定义
创建 Socket 实例时,必须指定三个关键参数:AddressFamily(地址族)、SocketType(套接字类型)和 ProtocolType(协议类型)。对于标准的以太网 TCP 服务,组合通常为 IPv4、流式套接字和 TCP 协议。
1. 地址族 (AddressFamily)
地址族决定了 Socket 将使用的寻址方案。以太网场景下主要关注以下枚举值:
public enum AddressFamily {
InterNetwork = 2, // IPv4 地址,最常用
InterNetworkV6 = 23,// IPv6 地址
Unknown = -1 // 未知地址族
}
2. 套接字类型 (SocketType)
定义了通信的信道特征。TCP 依赖可靠的双向数据流,因此选择 Stream:
public enum SocketType {
Stream = 1, // 面向连接、可靠的字节流(TCP 使用)
Dgram = 2, // 数据报,无连接(UDP 使用)
Raw = 3 // 原始套接字,常用于底层抓包或 ICMP
}
3. 协议类型 (ProtocolType)
指定在套接字之上使用的具体协议。对于 IP 版本 4 的 TCP 传输,固定使用 Tcp:
public enum ProtocolType {
Tcp = 6,
Udp = 17,
IP = 0,
Icmp = 1
}
服务端初始化与绑定操作
完成对象声明后,需按顺序执行绑定、监听和启动后台任务三个步骤,使服务器进入就绪状态。
第 1 步:实例化 Socket 对象
根据前述参数创建一个负责监听的 Socket 实例。注意 Socket 构造函数没有无参选项,必须传入上述组合。
// 声明服务对象
private Socket socketSever;
// 初始化:IPv4 + 流式 TCP
socketSever = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
第 2 步:绑定本地端点 (Bind)
创建一个 IPEndPoint 对象,指定服务器监听的 IP 地址和端口号,并将其绑定到 Socket 上。绑定失败通常意味着端口被占用或权限不足。
IPEndPoint ipe = new IPEndPoint(IPAddress.Parse("192.168.0.7"), 12345);
try
{
socketSever.Bind(ipe);
}
catch (Exception ex)
{
MessageBox.Show("服务器开启失败:" + ex.Message);
return;
}
第 3 步:开启监听 (Listen)
调用 Listen 方法并设置 backlog 参数,系统将为未处理的连接请求建立队列,防止客户端过多导致连接拒绝。
// 同时排队等待接受连接的数量
socketSever.Listen(10);
// 按钮状态更新
buttonStartService.Enabled = false;
第 4 步:启动后台接收线程
监听必须在非 UI 线程中运行,否则会阻塞界面。使用 Task.Run 启动新线程执行循环监听逻辑。
Task.Run(new Action(() =>
{
AcceptClients(); // 进入接受连接循环
}));
处理客户端连接与数据收发
服务端启动后,需要持续监听新连接的到来,并为每个已连接客户端分配独立的线程处理数据读写,以实现并发支持。
第 5 步:接受客户端连接 (Accept)
在 while 循环中调用 Accept 方法。该方法会阻塞直到有新连接请求。返回的 Socket 实例代表与该特定客户端的通道。
private void AcceptClients()
{
while (true)
{
// 阻塞等待客户端连接
Socket socketClient = socketSever.Accept();
string clientIP = socketClient.RemoteEndPoint.ToString();
// 假设存在管理连接的集合
clientPhoneBook.Add(clientIP, socketClient);
UpdateConnectionStatus(clientIP, true);
// 为每个客户端开启单独的接收线程
Task.Run(new Action(() =>
{
ReceiveData(socketClient);
}));
}
}
第 6 步:读取客户端数据 (Receive)
在每个客户端专属线程中,创建足够大的缓冲区(byte[])并使用 Receive 方法读取数据。需注意处理异常以判断客户端是否离线。
private void ReceiveData(Socket socketClient)
{
while (true)
{
byte[] buffer = new byte[1024 * 1024 * 10]; // 示例大缓冲区
int length = -1;
string client = socketClient.RemoteEndPoint.ToString();
try
{
// 阻塞读取数据
length = socketClient.Receive(buffer);
}
catch (Exception)
{
// 捕获到异常通常意味着对端断开连接
HandleClientDisconnect(client);
break;
}
if (length > 0)
{
// 成功读取数据,进行解码处理
string message = Encoding.UTF8.GetString(buffer, 0, length);
ProcessMessage(client, message);
}
else
{
// length 为 0 表示正常关闭连接
HandleClientDisconnect(client);
}
}
}
// 辅助方法:处理断开逻辑
private void HandleClientDisconnect(string clientIP)
{
UpdateConnectionStatus(clientIP, false);
clientPhoneBook.Remove(clientIP);
}
总结
C# 中的 Socket 网络编程核心在于理解地址族、类型与协议的对应关系,并通过 Bind、Listen、Accept 构建服务器骨架。结合多线程处理单个客户端的数据收发,可以构建出稳定且具备一定并发能力的以太网通信服务。以上就是 C# 以太网 Socket 服务器设计与实现的详细内容,更多关于 C# Socket 开发的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









