C#通讯关键类的API
12 个 C# 通讯核心类的完整 API 解析、实用细节及场景化示例,涵盖串口、Modbus、TCP/UDP、域名解析等场景,补充此前未覆盖的关键属性 / 方法(如Dns
域名解析、SerialPort
硬件控制),并强化实际开发中的易错点说明。
1. SerialPort
(串口通信)
命名空间:System.IO.Ports
核心功能:控制 RS-232/RS-485 串口设备,支持参数配置、数据收发,是硬件交互(如传感器、PLC)的核心类。
关键 API(含补充硬件控制)
类别 | 名称及说明 |
---|---|
基础配置 | PortName :串口名(如 "COM3",需通过SerialPort.GetPortNames() 获取系统可用串口)BaudRate :波特率(常见 9600/115200,需与设备一致)Parity :校验位(None /Odd /Even ,无校验最常用)DataBits :数据位(固定 8 位,硬件标准)StopBits :停止位(One /Two ,1 位最常用) |
硬件控制 | DtrEnable :是否启用 DTR(数据终端就绪)信号(部分设备需置true 才能通信)RtsEnable :是否启用 RTS(请求发送)信号(硬件流控必设)Handshake :流控方式(None /XOnXOff 软件流控 /RequestToSend 硬件流控) |
数据操作 | Open() /Close() :打开 / 关闭串口(需用try-catch 捕获占用 / 不存在异常)Write(byte[] buffer, int offset, int count) :发送字节数组Read(byte[] buffer, int offset, int count) :读取指定长度字节ReadLine() :读取一行(直到NewLine ,适合文本协议)DataReceived :数据接收事件(注意:事件在子线程触发,跨 UI 需 Invoke) |
缓存与超时 | BytesToRead :接收缓冲区待读字节数DiscardInBuffer() /DiscardOutBuffer() :清空接收 / 发送缓存ReadTimeout /WriteTimeout :读写超时(毫秒,超时抛TimeoutException ) |
示例(带硬件流控的 PLC 串口通信)
using System; using System.IO.Ports; using System.Windows.Forms; // 若需UI交互 class PlcSerialComm {private SerialPort _plcPort;private TextBox _logTextBox; // UI文本框(用于显示日志) public PlcSerialComm(TextBox logTextBox){_logTextBox = logTextBox;_plcPort = new SerialPort{PortName = "COM4",BaudRate = 115200,Parity = Parity.Even,DataBits = 8,StopBits = StopBits.One,Handshake = Handshake.RequestToSend, // PLC常用硬件流控RtsEnable = true, // 启用RTS信号ReadTimeout = 2000,NewLine = "\r\n" // PLC文本协议常用换行符};// 绑定接收事件_plcPort.DataReceived += PlcPort_DataReceived;} public void StartComm(){try{if (!_plcPort.IsOpen) _plcPort.Open();Log("串口已打开,等待PLC数据...");// 发送PLC读取指令(示例:读取状态寄存器)byte[] readCmd = { 0x01, 0x02, 0x00, 0x00, 0x00, 0x08, 0x28, 0x0A };_plcPort.Write(readCmd, 0, readCmd.Length);}catch (UnauthorizedAccessException){Log("错误:串口被占用或无权限");}catch (IOException){Log("错误:串口不存在或设备未连接");}} // 接收事件(子线程,需跨UIInvoke)private void PlcPort_DataReceived(object sender, SerialDataReceivedEventArgs e){if (_plcPort.BytesToRead == 0) return;byte[] recvData = new byte[_plcPort.BytesToRead];_plcPort.Read(recvData, 0, recvData.Length);// 跨UI线程更新日志_logTextBox.Invoke(new Action(() => Log($"收到PLC数据:{BitConverter.ToString(recvData)}")));} private void Log(string msg) => _logTextBox.AppendText($"[{DateTime.Now:HH:mm:ss}] {msg}\r\n"); }
2. SerialDataReceivedEventArgs
(串口接收事件参数)
命名空间:System.IO.Ports
核心功能:为SerialPort.DataReceived
事件提供上下文,区分接收数据类型。
关键 API
属性名 | 说明 |
---|---|
EventType | 接收数据类型(枚举SerialData ):- Chars :常规字符 / 字节数据(99% 场景)- Eof :流结束符(仅部分设备支持,如 Ctrl+Z) |
示例(根据数据类型处理)
private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e) {var port = sender as SerialPort;if (port == null || !port.IsOpen) return; switch (e.EventType){case SerialData.Chars:// 处理常规字节数据byte[] data = new byte[port.BytesToRead];port.Read(data, 0, data.Length);Console.WriteLine($"接收字节:{BitConverter.ToString(data)}");break;case SerialData.Eof:// 处理流结束(如设备断开连接的信号)Console.WriteLine("收到流结束符,设备可能已断开");port.Close();break;} }
3. ModbusSerialMaster
(Modbus RTU 主站)
命名空间:Modbus.Device
(第三方库NModbus
,需通过 NuGet 安装:Install-Package NModbus
)
核心功能:封装 Modbus RTU 协议(串口),简化 “主站 - 从站” 通信(如读取传感器寄存器、控制 PLC 输出)。
关键 API(Modbus 核心功能)
方法名 | 说明 |
---|---|
CreateRtu(SerialPort serialPort) | 静态方法:通过已初始化的SerialPort 创建 RTU 主站实例 |
ReadHoldingRegisters(byte slaveAddr, ushort startAddr, ushort count) | 读取保持寄存器(地址 0-65535,返回ushort[] ,对应 Modbus 功能码 03) |
ReadInputRegisters(byte slaveAddr, ushort startAddr, ushort count) | 读取输入寄存器(只读,对应功能码 04) |
ReadCoils(byte slaveAddr, ushort startAddr, ushort count) | 读取线圈(开关量,0=OFF/1=ON,对应功能码 01) |
WriteSingleRegister(byte slaveAddr, ushort regAddr, ushort value) | 写入单个保持寄存器(对应功能码 06) |
WriteMultipleCoils(byte slaveAddr, ushort startAddr, bool[] values) | 写入多个线圈(对应功能码 15) |
Transport.ReadTimeout /WriteTimeout | 通信超时(毫秒,默认 1000,需根据设备响应调整) |
示例(RTU 主站读取温湿度传感器)
using System; using System.IO.Ports; using Modbus.Device; class ModbusRtuSensorReader {static void Main(){// 1. 初始化串口(与传感器RTU参数一致)using (var serialPort = new SerialPort("COM5"){BaudRate = 9600,Parity = Parity.None,DataBits = 8,StopBits = StopBits.One,ReadTimeout = 3000}){serialPort.Open(); // 2. 创建RTU主站using (var master = ModbusSerialMaster.CreateRtu(serialPort)){master.Transport.ReadTimeout = 2000; // 延长超时(传感器可能响应慢)byte slaveAddr = 1; // 传感器从站地址(硬件配置,如拨码开关) try{// 3. 读取寄存器:温度(地址0)、湿度(地址1)(功能码03)ushort[] registers = master.ReadHoldingRegisters(slaveAddr, 0, 2);// 4. 解析数据(假设传感器返回值为“数值*0.1”,如0x01F4=500 → 50.0℃)float temperature = registers[0] * 0.1f;float humidity = registers[1] * 0.1f;Console.WriteLine($"当前温度:{temperature:0.0}℃,湿度:{humidity:0.0}%");}catch (ModbusTimeoutException){Console.WriteLine("错误:传感器无响应(超时)");}catch (ModbusSlaveException ex){Console.WriteLine($"传感器异常:功能码{ex.SlaveExceptionCode}(如地址无效)");}}}} }
4. ModbusIpMaster
(Modbus TCP 主站)
命名空间:Modbus.Device
(NModbus
库)
核心功能:封装 Modbus TCP 协议(以太网),用于主站与 TCP 从站(如 Modbus 网关、工业交换机)通信,无需串口硬件。
关键 API(与 RTU 差异点)
方法名 | 说明 |
---|---|
CreateIp(TcpClient tcpClient) | 静态方法:通过TcpClient 创建 TCP 主站(TCP 连接替代串口) |
ReadHoldingRegisters(byte unitId, ushort startAddr, ushort count) | 读取保持寄存器(参数unitId 替代 RTU 的slaveAddr ,对应 TCP 帧的 “单元 ID”) |
其他方法(如WriteSingleRegister ) | 参数与 RTU 一致,仅底层协议为 TCP(端口默认 502) |
示例(TCP 主站控制 Modbus 网关输出)
using System; using System.Net.Sockets; using Modbus.Device; class ModbusTcpGatewayControl {static void Main(){// 1. 连接Modbus TCP从站(网关IP:192.168.1.200,端口502)using (var tcpClient = new TcpClient()){tcpClient.Connect("192.168.1.200", 502);Console.WriteLine("已连接Modbus网关"); // 2. 创建TCP主站using (var master = ModbusIpMaster.CreateIp(tcpClient)){byte unitId = 1; // 网关单元ID(配置工具设置)try{// 3. 控制网关继电器(写入线圈:地址0=ON,对应功能码15)bool[] relayStates = { true }; // 继电器1闭合master.WriteMultipleCoils(unitId, 0, relayStates);Console.WriteLine("继电器1已闭合"); // 4. 验证状态(读取线圈,确认是否生效)bool[] currentStates = master.ReadCoils(unitId, 0, 1);Console.WriteLine($"继电器当前状态:{(currentStates[0] ? "ON" : "OFF")}");}catch (SocketException){Console.WriteLine("错误:网关断开连接或IP/端口错误");}}}} }
5. Socket
(底层网络通信)
命名空间:System.Net.Sockets
核心功能:最底层的网络通信类,支持 TCP/UDP/RAW 协议,灵活控制字节流,适合自定义协议开发(如物联网私有协议)。
关键 API(TCP/UDP 通用)
类别 | 名称及说明 |
---|---|
初始化 | Socket(AddressFamily family, SocketType type, ProtocolType protocol) :- family :InterNetwork (IPv4)/InterNetworkV6 (IPv6)- type :Stream (TCP,面向连接)/Dgram (UDP,无连接)- protocol :Tcp /Udp |
TCP 操作 | Bind(EndPoint localEp) :绑定本地 IP + 端口(服务器必用)Listen(int backlog) :开始监听(服务器,backlog 为最大等待队列)Accept() /AcceptAsync() :接受客户端连接(返回新Socket 用于通信)Connect(EndPoint remoteEp) :客户端连接服务器 |
UDP 操作 | SendTo(byte[] buffer, EndPoint remoteEp) :发送 UDP 数据报到指定端点(无需连接)ReceiveFrom(byte[] buffer, ref EndPoint remoteEp) :接收 UDP 数据报(获取发送端地址) |
通用操作 | Send(byte[] buffer) :TCP 发送数据(需先连接)Receive(byte[] buffer) :读取数据(TCP 阻塞,UDP 需用ReceiveFrom )SetSocketOption(SocketOptionLevel level, SocketOptionName name, object value) :设置选项(如ReuseAddress 允许端口复用)Shutdown(SocketShutdown how) :关闭发送 / 接收通道(Send /Receive /Both )Close() :关闭 Socket(释放资源) |
示例(UDP 自定义协议数据收发)
using System; using System.Net; using System.Net.Sockets; using System.Text; class UdpCustomProtocol {static void Main(){// UDP Socket(IPv4,无连接)using (var udpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)){// 绑定本地端口(接收用,发送可省略)IPEndPoint localEp = new IPEndPoint(IPAddress.Any, 9000);udpSocket.Bind(localEp);Console.WriteLine("UDP Socket已绑定端口9000,等待数据..."); // 1. 接收客户端数据byte[] recvBuffer = new byte[1024];EndPoint clientEp = new IPEndPoint(IPAddress.Any, 0); // 用于存储发送端地址int recvLen = udpSocket.ReceiveFrom(recvBuffer, ref clientEp);string recvMsg = Encoding.UTF8.GetString(recvBuffer, 0, recvLen);Console.WriteLine($"收到来自{clientEp}的消息:{recvMsg}"); // 2. 发送响应(自定义协议:前缀"ACK:")string response = $"ACK:{recvMsg}";byte[] sendBuffer = Encoding.UTF8.GetBytes(response);udpSocket.SendTo(sendBuffer, clientEp);Console.WriteLine("已发送响应");}} }
6. TcpListener
(TCP 服务器封装)
命名空间:System.Net.Sockets
核心功能:封装Socket
的 TCP 服务器逻辑(Bind
/Listen
/Accept
),简化服务器开发,无需直接操作底层Socket
。
关键 API
方法名 | 说明 |
---|---|
TcpListener(IPAddress localAddr, int port) | 构造函数:绑定本地 IP(IPAddress.Any 表示所有网卡)和端口 |
Start() /Stop() | 启动 / 停止监听(Stop() 会关闭所有已接受的TcpClient ) |
AcceptTcpClient() /AcceptTcpClientAsync() | 接受客户端连接(返回TcpClient ,用于与该客户端通信)- 同步方法阻塞,异步方法适合高并发 |
Pending() | 检查是否有等待连接(返回bool ,非阻塞,用于轮询) |
示例(异步 TCP 服务器,支持多客户端)
using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; class AsyncTcpServer {static async Task Main(){// 监听所有网卡的8080端口var listener = new TcpListener(IPAddress.Any, 8080);listener.Start();Console.WriteLine("TCP服务器已启动,等待客户端连接..."); try{// 循环接受客户端(异步,不阻塞)while (true){TcpClient client = await listener.AcceptTcpClientAsync();Console.WriteLine($"新客户端连接:{client.Client.RemoteEndPoint}");// 单独线程处理客户端(避免阻塞接受新连接)_ = HandleClientAsync(client); // _ 忽略Task返回值(后台处理)}}finally{listener.Stop();}} // 异步处理单个客户端通信private static async Task HandleClientAsync(TcpClient client){using (client) // 自动释放客户端资源using (NetworkStream stream = client.GetStream()){byte[] buffer = new byte[1024];int bytesRead;// 循环读取客户端数据(直到客户端断开)while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length)) > 0){string clientMsg = Encoding.UTF8.GetString(buffer, 0, bytesRead);Console.WriteLine($"来自{client.Client.RemoteEndPoint}:{clientMsg}"); // 发送响应string response = $"Server Echo: {clientMsg}";byte[] responseBuffer = Encoding.UTF8.GetBytes(response);await stream.WriteAsync(responseBuffer, 0, responseBuffer.Length);}Console.WriteLine($"客户端{client.Client.RemoteEndPoint}已断开");}} }
7. UdpClient
(UDP 封装)
命名空间:System.Net.Sockets
核心功能:封装Socket
的 UDP 操作,简化数据报收发,支持多播 / 广播,无需手动处理Socket
选项。
关键 API(补充多播 / 广播)
类别 | 名称及说明 |
---|---|
基础操作 | UdpClient(int port) :绑定本地端口(接收必用)Send(byte[] dgram, int bytes, IPEndPoint remoteEp) :发送数据报到指定端点Receive(ref IPEndPoint remoteEp) /ReceiveAsync() :接收数据报(获取发送端地址) |
多播支持 | JoinMulticastGroup(IPAddress multicastAddr) :加入多播组(如224.0.0.100 ,多设备共享数据)LeaveMulticastGroup(IPAddress multicastAddr) :离开多播组 |
广播支持 | EnableBroadcast = true :启用广播(必须设置,否则无法发送广播包)广播地址:IPAddress.Broadcast (255.255.255.255 ,局域网所有设备) |
示例(UDP 多播数据分发)
using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; class UdpMulticastDemo {// 多播组地址(需在224.0.0.0~239.255.255.255范围内)private static readonly IPAddress _multicastAddr = IPAddress.Parse("224.0.0.100");private const int _multicastPort = 9001; // 多播发送端(如数据采集器)static async Task SenderAsync(){using (var udpClient = new UdpClient()){udpClient.EnableBroadcast = false; // 多播无需广播IPEndPoint multicastEp = new IPEndPoint(_multicastAddr, _multicastPort); // 循环发送数据(每秒1次)for (int i = 0; i < 10; i++){string data = $"Multicast Data {i} - {DateTime.Now:HH:mm:ss}";byte[] buffer = Encoding.UTF8.GetBytes(data);await udpClient.SendAsync(buffer, buffer.Length, multicastEp);Console.WriteLine($"发送多播数据:{data}");await Task.Delay(1000);}}} // 多播接收端(如多个监控终端)static async Task ReceiverAsync(string receiverName){using (var udpClient = new UdpClient(_multicastPort)){// 加入多播组(必须操作,否则收不到多播数据)udpClient.JoinMulticastGroup(_multicastAddr);Console.WriteLine($"{receiverName}已加入多播组,等待数据..."); IPEndPoint senderEp = new IPEndPoint(IPAddress.Any, 0);while (true){// 异步接收多播数据UdpReceiveResult result = await udpClient.ReceiveAsync();string data = Encoding.UTF8.GetString(result.Buffer);Console.WriteLine($"{receiverName}收到:{data}(来自{result.RemoteEndPoint})");}}} static void Main(){// 启动发送端和两个接收端(多线程)_ = SenderAsync();_ = ReceiverAsync("监控终端1");_ = ReceiverAsync("监控终端2");Console.ReadLine(); // 阻塞主线程} }
8. Stream
(抽象流基类)
命名空间:System.IO
核心功能:所有字节流的抽象基类(如NetworkStream
/FileStream
/MemoryStream
),定义统一的读写接口,支持 “多态” 操作(如用同一逻辑处理网络流和文件流)。
关键 API(抽象方法,子类实现)
方法 / 属性 | 说明 |
---|---|
核心操作 | Read(byte[] buffer, int offset, int count) :从流读字节(返回实际读取长度,0 表示流结束)Write(byte[] buffer, int offset, int count) :向流写字节Flush() :刷新缓冲区(网络流 / 文件流需调用,避免数据滞留) |
状态判断 | CanRead /CanWrite :是否支持读写(如断开的NetworkStream 为false )CanSeek :是否支持定位(NetworkStream 为false ,FileStream 为true )Length :流长度(仅CanSeek=true 可用) |
异步操作 | ReadAsync(byte[] buffer, int offset, int count) /WriteAsync(...) :异步读写(非阻塞)CopyToAsync(Stream destination) :异步复制流数据(如网络流→文件流) |
示例(多态处理流:网络流保存到文件)
using System; using System.IO; using System.Net.Sockets; using System.Threading.Tasks; class StreamPolymorphismDemo {// 通用流保存方法(接收任何Stream子类)private static async Task SaveStreamToFileAsync(Stream sourceStream, string filePath){if (!sourceStream.CanRead)throw new InvalidOperationException("流不支持读取"); // 用FileStream作为目标流(多态:sourceStream可为NetworkStream/MemoryStream等)using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write)){Console.WriteLine($"开始保存流到:{filePath}");await sourceStream.CopyToAsync(fileStream); // 异步复制(自动处理缓冲)await fileStream.FlushAsync(); // 确保数据写入磁盘Console.WriteLine("保存完成");}} static async Task Main(){// 1. 从TCP服务器获取网络流using (var tcpClient = new TcpClient()){await tcpClient.ConnectAsync("192.168.1.300", 8080);using (NetworkStream netStream = tcpClient.GetStream()){// 2. 调用通用方法,将网络流保存到本地文件await SaveStreamToFileAsync(netStream, "received_data.bin");}} // 3. 测试:用MemoryStream调用同一方法(多态验证)using (var memoryStream = new MemoryStream()){// 向内存流写入测试数据byte[] testData = System.Text.Encoding.UTF8.GetBytes("Test Memory Stream Data");await memoryStream.WriteAsync(testData, 0, testData.Length);memoryStream.Position = 0; // 重置流指针(否则Read会从末尾开始)// 保存内存流到文件await SaveStreamToFileAsync(memoryStream, "memory_data.txt");}} }
9. Encoding
(字符编码)
命名空间:System.Text
核心功能:处理 “字符串 - 字节数组” 转换,解决多语言编码问题(如中文 UTF-8/GB2312、英文 ASCII),是通讯中 “文本协议” 的核心工具。
关键 API(补充编码兼容性)
类别 | 名称及说明 |
---|---|
预定义编码 | Encoding.UTF8 :UTF-8 编码(推荐,支持所有语言,无 BOM)Encoding.ASCII :ASCII 编码(仅英文,中文转? )Encoding.Unicode :UTF-16 编码(双字节,Windows 内部常用)Encoding.Default :系统默认编码(Windows=GB2312,Linux=UTF-8,跨平台不推荐) |
自定义编码 | Encoding.GetEncoding(int codePage) :通过代码页获取编码(如936 =GB2312,65001 =UTF-8,950 =Big5)Encoding.GetEncoding(string name) :通过名称获取(如"gb2312" /"utf-8" ) |
转换操作 | GetBytes(string s) :字符串→字节数组GetString(byte[] bytes, int index, int count) :字节数组→字符串(指定起始位置和长度,避免冗余数据)GetByteCount(string s) :计算字符串对应的字节长度(预分配缓冲区,提升性能) |
示例(多编码转换:GB2312 与 UTF-8 互转)
using System; using System.Text;class EncodingConversionDemo {static void Main(){// 原始中文字符串string chineseText = "通讯测试:C# Encoding";// 1. UTF-8 → GB2312(如向旧设备发送GB2312数据)byte[] utf8Bytes = Encoding.UTF8.GetBytes(chineseText);// 先将UTF-8字节转成字符串(避免编码丢失),再转GB2312string tempText = Encoding.UTF8.GetString(utf8Bytes);byte[] gb2312Bytes = Encoding.GetEncoding(936).GetBytes(tempText);Console.WriteLine($"UTF-8→GB2312字节:{BitConverter.ToString(gb2312Bytes)}");// 2. GB2312 → UTF-8(如接收旧设备GB2312数据,转UTF-8显示)string gb2312Text = Encoding.GetEncoding(936).GetString(gb2312Bytes);byte[] utf8Bytes2 = Encoding.UTF8.GetBytes(gb2312Text);string finalText = Encoding.UTF8.GetString(utf8Bytes2);Console.WriteLine($"GB2312→UTF-8结果:{finalText}");// 3. 避免常见错误:直接用错误编码解析string wrongText = Encoding.ASCII.GetString(gb2312Bytes);Console.WriteLine($"错误编码(ASCII)解析结果:{wrongText}"); // 中文显示为?} }
10. Dns
(域名解析)
命名空间:System.Net
核心功能:将域名(如www.baidu.com
)解析为 IP 地址,或反向解析 IP 到域名,是网络通信中 “域名转 IP” 的核心类。
关键 API(异步优先)
方法名 | 说明 |
---|---|
正向解析 | GetHostAddressesAsync(string hostNameOrAddress) :异步解析域名到 IP 数组(支持 IPv4/IPv6,返回IPAddress[] )GetHostEntryAsync(string hostNameOrAddress) :异步获取主机条目(包含 IP、主机名、别名,返回IPHostEntry ) |
反向解析 | GetHostEntryAsync(IPAddress address) :异步将 IP 解析为域名(依赖 DNS 反向记录,可能返回空) |
同步方法 | GetHostAddresses(string hostName) /GetHostEntry(string hostName) :同步解析(不推荐,会阻塞线程) |
示例(异步解析域名并连接服务器)
using System; using System.Net; using System.Net.Sockets; using System.Threading.Tasks;class DnsResolverDemo {static async Task Main(){string domain = "www.baidu.com"; // 待解析域名int port = 80; // HTTP端口try{// 1. 异步解析域名(获取所有IP地址)Console.WriteLine($"正在解析域名:{domain}");IPAddress[] ipAddresses = await Dns.GetHostAddressesAsync(domain);// 筛选IPv4地址(避免IPv6连接问题)IPAddress ipv4Addr = Array.Find(ipAddresses, ip => ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork);if (ipv4Addr == null){Console.WriteLine("未找到IPv4地址");return;}Console.WriteLine($"解析到IPv4地址:{ipv4Addr}");// 2. 用解析后的IP连接服务器using (var tcpClient = new TcpClient()){await tcpClient.ConnectAsync(ipv4Addr, port);Console.WriteLine($"已连接到 {domain}({ipv4Addr}:{port})");}}catch (SocketException ex){Console.WriteLine($"连接错误:{ex.Message}");}catch (Exception ex){Console.WriteLine($"解析错误:{ex.Message}(如域名不存在、DNS不可用)");}} }
11. IPAddress
(IP 地址封装)
命名空间:System.Net
核心功能:表示 IPv4/IPv6 地址,提供地址解析、验证、格式转换,是IPEndPoint
、Socket
的基础参数。
关键 API(补充地址验证与转换)
类别 | 名称及说明 |
---|---|
地址创建 | IPAddress.Parse(string ipString) :解析 IP 字符串(如"192.168.1.1" ),无效则抛FormatException``IPAddress.TryParse(string ipString, out IPAddress result) :安全解析(返回bool ,不抛异常,推荐) |
预定义地址 | IPAddress.Any :匹配所有本地网卡 IP(服务器绑定用,如0.0.0.0 )IPAddress.Loopback :回环地址(127.0.0.1 ,本地测试用)IPAddress.Broadcast :广播地址(255.255.255.255 ,UDP 广播用) |
属性 | AddressFamily :地址族(InterNetwork =IPv4,InterNetworkV6 =IPv6)IsIPv4MappedToIPv6 :是否为 IPv4 映射的 IPv6 地址ToString() :将 IP 地址转为字符串(如"192.168.1.1" ) |
示例(IP 地址验证与筛选)
using System; using System.Net; using System.Linq;class IPAddressValidationDemo {static void Main(){// 1. 安全解析IP(避免异常)string[] testIps = { "192.168.1.100", "256.0.0.1", "fe80::1", "invalid.ip" };foreach (string ipStr in testIps){if (IPAddress.TryParse(ipStr, out IPAddress ip)){string ipType = ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork ? "IPv4" : "IPv6";Console.WriteLine($"有效{ipType}地址:{ip}");}else{Console.WriteLine($"无效IP地址:{ipStr}");}}// 2. 解析域名后筛选IPv4(结合Dns)IPAddress[] baiduIps = Dns.GetHostAddresses("www.baidu.com");IPAddress[] baiduIpv4 = baiduIps.Where(ip => ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork).ToArray();Console.WriteLine($"\n百度IPv4地址列表:{string.Join(", ", baiduIpv4)}");// 3. 回环地址测试(本地服务)IPAddress loopback = IPAddress.Loopback;Console.WriteLine($"回环地址:{loopback}(用于本地程序通信)");} }
12. NetworkStream
(网络流)
命名空间:System.Net.Sockets
核心功能:封装Socket
的网络数据流,支持 TCP/UDP(主要用于 TCP)的字节读写,继承自Stream
,可与其他流类(如FileStream
)协同工作。
关键 API(补充超时与状态)
类别 | 名称及说明 |
---|---|
构造与状态 | NetworkStream(Socket socket) :通过Socket 创建网络流CanTimeout :是否支持超时(始终true )ReadTimeout /WriteTimeout :读写超时(毫秒,默认无限期,需手动设置避免阻塞) |
流操作 | Read(byte[] buffer, int offset, int count) :读取网络数据(TCP 阻塞,UDP 需用UdpClient )Write(byte[] buffer, int offset, int count) :发送网络数据Flush() :刷新缓冲区(TCP 需调用,确保数据发送) |
连接控制 | Close(int timeout) :关闭流并等待指定时间(毫秒),确保数据发送完成Dispose(bool disposing) :释放资源(using 语句自动调用) |
示例(带超时的 TCP 网络流读写)
using System; using System.Net.Sockets; using System.Text; using System.Threading.Tasks;class NetworkStreamTimeoutDemo {static async Task Main(){using (var tcpClient = new TcpClient()){try{// 连接超时(需通过TcpClient.ConnectAsync的CancellationToken实现)var connectTask = tcpClient.ConnectAsync("192.168.1.400", 8080);if (await Task.WhenAny(connectTask, Task.Delay(3000)) != connectTask){throw new TimeoutException("连接超时(3秒)");}using (NetworkStream netStream = tcpClient.GetStream()){// 设置流超时(避免Read/Write无限阻塞)netStream.ReadTimeout = 2000;netStream.WriteTimeout = 2000;// 发送数据string sendMsg = "Hello NetworkStream with Timeout";byte[] sendBuffer = Encoding.UTF8.GetBytes(sendMsg);await netStream.WriteAsync(sendBuffer, 0, sendBuffer.Length);await netStream.FlushAsync();Console.WriteLine($"已发送:{sendMsg}");// 接收响应(带超时)byte[] recvBuffer = new byte[1024];int recvLen = await netStream.ReadAsync(recvBuffer, 0, recvBuffer.Length);if (recvLen == 0){Console.WriteLine("服务器关闭连接");return;}string recvMsg = Encoding.UTF8.GetString(recvBuffer, 0, recvLen);Console.WriteLine($"收到响应:{recvMsg}");}}catch (TimeoutException ex){Console.WriteLine($"超时错误:{ex.Message}");}catch (SocketException ex){Console.WriteLine($"网络错误:{ex.Message}");}}} }
13. IPEndPoint
(IP 端点)
命名空间:System.Net
核心功能:表示 “IP 地址 + 端口” 的组合,标识网络中的唯一端点(如服务器192.168.1.1:8080
),是Socket
、UdpClient
、TcpListener
的核心参数。
关键 API
类别 | 名称及说明 |
---|---|
构造函数 | IPEndPoint(IPAddress address, int port) :创建端点(port 范围 1-65535,0 为随机端口) |
属性 | Address :获取端点的IPAddress 对象Port :获取端点的端口号AddressFamily :获取地址族(与Address 一致)ToString() :转为字符串(如"192.168.1.1:8080" ) |
静态方法 | Create(EndPoint endPoint) :将通用EndPoint 转为IPEndPoint (类型转换) |
示例(创建本地 / 远程端点并通信)
using System; using System.Net; using System.Net.Sockets; using System.Text;class IPEndPointDemo {static void Main(){// 1. 创建远程端点(服务器地址)IPAddress serverIp = IPAddress.Parse("192.168.1.500");int serverPort = 9002;IPEndPoint serverEp = new IPEndPoint(serverIp, serverPort);Console.WriteLine($"远程服务器端点:{serverEp}");// 2. 创建本地端点(客户端绑定固定端口,可选)IPAddress localIp = IPAddress.Any; // 自动选择本地IPint localPort = 9003;IPEndPoint localEp = new IPEndPoint(localIp, localPort);Console.WriteLine($"本地客户端端点:{localEp}");// 3. 用Socket绑定本地端点并连接远程端点using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)){socket.Bind(localEp); // 绑定本地端口(客户端可选,服务器必选)socket.Connect(serverEp);Console.WriteLine("已连接到服务器");// 发送数据byte[] data = Encoding.UTF8.GetBytes("Hello IPEndPoint");socket.Send(data);Console.WriteLine("已发送数据");// 接收响应byte[] recvBuffer = new byte[1024];int recvLen = socket.Receive(recvBuffer);string recvMsg = Encoding.UTF8.GetString(recvBuffer, 0, recvLen);Console.WriteLine($"收到响应:{recvMsg}");}} }
补充说明(实际开发必看)
资源释放:所有实现
IDisposable
的类(如SerialPort
、Socket
、Stream
)必须用using
语句包裹,避免端口 / 句柄泄漏。异步优先:UI 程序或高并发服务需用
Async/Await
(如ConnectAsync
、ReadAsync
),避免主线程阻塞。异常处理:
串口:
UnauthorizedAccessException
(权限)、IOException
(设备断开)、TimeoutException
(超时)网络:
SocketException
(IP / 端口错误、断网)、TimeoutException
(连接 / 读写超时)Modbus:
ModbusTimeoutException
(从站无响应)、ModbusSlaveException
(从站异常码)
库依赖:Modbus 类需安装
NModbus
,NuGet 命令:Install-Package NModbus
(.NET Framework)或Install-Package NModbus4
(.NET Core/.NET 5+)。编码注意:中文通信优先用 UTF-8,旧设备用 GB2312(代码页 936),避免乱码。