前言
在工业自动化、物联网设备管理、远程监控等应用场景中,经常需要将本地串口设备(如条码扫描枪、RFID读卡器、各类传感器)的数据实时传输到远程服务器进行处理。本文将详细介绍如何使用 C# 创建一个串口监听服务,并将接收到的数据通过 TCP 协议转发至远程服务器。
本方案实现的功能非常实用且简洁:当串口设备有数据输入时,程序自动捕获并将其转发至指定的 TCP 服务器。适用于远程数据采集、设备状态监控、嵌入式系统通信等多种场景。
正文
一、实现原理
整个程序基于以下核心步骤构建:
1、创建串口监听服务:配置并打开串口,注册数据接收事件;
2、监听串口数据变化:通过 DataReceived
事件捕获新数据;
3、建立 TCP 连接:将接收到的数据通过 TCP 客户端发送到远程服务器;
4、实现重连机制:在网络异常中断后自动尝试重新连接;
5、资源释放与异常处理:确保程序退出或异常时能正确关闭串口和网络连接,避免资源泄漏。
二、代码实现
using System;
using System.IO.Ports;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespaceAppComTransTcp
{
internalclassProgram
{
// TCP客户端
privatestatic TcpClient _tcpClient;
// 网络数据流
privatestatic NetworkStream _networkStream;
// 串口对象
privatestatic SerialPort _serialPort;
// TCP服务器IP地址
privatestaticstring _serverIp = "127.0.0.1";
// TCP服务器端口
privatestaticint _serverPort = 3001;
// 串口名称
privatestaticstring _portName = "COM1";
// 波特率
privatestaticint _baudRate = 9600;
// 数据位
privatestaticint _dataBits = 8;
// 停止位
privatestatic StopBits _stopBits = StopBits.One;
// 校验位
privatestatic Parity _parity = Parity.None;
// 重连间隔(毫秒)
privatestaticint _reconnectInterval = 5000;
// 是否继续运行
privatestaticbool _isRunning = true;
static void Main(string[] args)
{
Console.WriteLine("串口TCP转发服务启动中...");
// 初始化并启动服务
InitializeService();
Console.WriteLine("服务已启动。按 'q' 退出程序。");
// 保持程序运行,直到用户输入q退出
while (_isRunning)
{
var key = Console.ReadKey(true);
if (key.KeyChar == 'q' || key.KeyChar == 'Q')
{
_isRunning = false;
}
}
// 关闭资源
CloseConnections();
Console.WriteLine("程序已退出。");
}
/// <summary>
/// 初始化服务,包括串口和TCP连接
/// </summary>
private static void InitializeService()
{
try
{
// 初始化串口
InitializeSerialPort();
// 初始化TCP连接
ConnectToTcpServer();
// 启动重连检查任务
StartReconnectionTask();
}
catch (Exception ex)
{
Console.WriteLine($"初始化服务失败: {ex.Message}");
}
}
/// <summary>
/// 初始化串口设置
/// </summary>
private static void InitializeSerialPort()
{
try
{
// 创建并配置串口对象
_serialPort = new SerialPort
{
PortName = _portName,
BaudRate = _baudRate,
DataBits = _dataBits,
StopBits = _stopBits,
Parity = _parity,
ReadBufferSize = 4096,
ReadTimeout = 500
};
// 注册数据接收事件
_serialPort.DataReceived += SerialPort_DataReceived;
// 打开串口
_serialPort.Open();
Console.WriteLine($"串口 {_portName} 已成功打开,波特率: {_baudRate}");
}
catch (Exception ex)
{
Console.WriteLine($"初始化串口失败: {ex.Message}");
throw;
}
}
/// <summary>
/// 建立TCP服务器连接
/// </summary>
private static void ConnectToTcpServer()
{
try
{
// 创建TCP客户端并连接服务器
_tcpClient = new TcpClient();
_tcpClient.Connect(_serverIp, _serverPort);
_networkStream = _tcpClient.GetStream();
Console.WriteLine($"已成功连接到TCP服务器 {_serverIp}:{_serverPort}");
}
catch (Exception ex)
{
Console.WriteLine($"连接TCP服务器失败: {ex.Message}");
// 这里不抛出异常,让重连机制处理
}
}
/// <summary>
/// 启动TCP重连检查任务
/// </summary>
private static void StartReconnectionTask()
{
Task.Run(async () =>
{
while (_isRunning)
{
try
{
// 检查TCP连接状态
if (_tcpClient == null || !_tcpClient.Connected)
{
Console.WriteLine("TCP连接已断开,尝试重新连接...");
// 关闭旧连接
if (_tcpClient != null)
{
_tcpClient.Close();
_tcpClient.Dispose();
}
// 创建新连接
ConnectToTcpServer();
}
}
catch (Exception ex)
{
Console.WriteLine($"重连过程发生错误: {ex.Message}");
}
// 等待指定时间后再次检查
await Task.Delay(_reconnectInterval);
}
});
}
/// <summary>
/// 串口数据接收事件处理
/// </summary>
private static void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
// 确保有足够的数据可读
if (_serialPort.BytesToRead <= 0)
return;
// 读取串口数据
byte[] buffer = newbyte[_serialPort.BytesToRead];
_serialPort.Read(buffer, 0, buffer.Length);
// 转换为字符串(可根据实际需求修改编码方式)
string data = Encoding.UTF8.GetString(buffer);
Console.WriteLine($"接收到串口数据: {data}");
// 将数据转发到TCP服务器
SendDataToTcpServer(buffer);
}
catch (Exception ex)
{
Console.WriteLine($"处理串口数据时发生错误: {ex.Message}");
}
}
/// <summary>
/// 发送数据到TCP服务器
/// </summary>
private static void SendDataToTcpServer(byte[] data)
{
try
{
// 检查TCP连接是否可用
if (_tcpClient != null && _tcpClient.Connected && _networkStream != null)
{
// 发送数据
_networkStream.Write(data, 0, data.Length);
_networkStream.Flush();
Console.WriteLine($"已发送 {data.Length} 字节数据到TCP服务器");
}
else
{
Console.WriteLine("TCP连接不可用,数据发送失败");
}
}
catch (Exception ex)
{
Console.WriteLine($"发送数据到TCP服务器失败: {ex.Message}");
// 标记连接为断开,让重连机制处理
if (_tcpClient != null)
{
_tcpClient.Close();
}
}
}
/// <summary>
/// 关闭所有连接并释放资源
/// </summary>
private static void CloseConnections()
{
try
{
// 关闭串口
if (_serialPort != null && _serialPort.IsOpen)
{
_serialPort.DataReceived -= SerialPort_DataReceived;
_serialPort.Close();
_serialPort.Dispose();
Console.WriteLine("串口已关闭");
}
// 关闭TCP连接
if (_networkStream != null)
{
_networkStream.Close();
_networkStream.Dispose();
}
if (_tcpClient != null)
{
_tcpClient.Close();
_tcpClient.Dispose();
Console.WriteLine("TCP连接已关闭");
}
}
catch (Exception ex)
{
Console.WriteLine($"关闭连接时发生错误: {ex.Message}");
}
}
}
}
三、功能详解
1、串口监听服务
使用 SerialPort
类实现串口监听,支持自定义配置如下:
示例配置:
_serialPort = new SerialPort
{
PortName = _portName,
BaudRate = _baudRate,
DataBits = _dataBits,
StopBits = _stopBits,
Parity = _parity,
ReadBufferSize = 4096,
ReadTimeout = 500
};
2、数据变化检测与转发
通过注册 DataReceived
事件实现串口数据变化检测:
_serialPort.DataReceived += SerialPort_DataReceived;
当串口接收到数据后,事件处理程序自动触发:
1、读取缓冲区数据;
2、将其转换为字符串;
3、调用 SendDataToTcpServer
方法将数据转发到 TCP 服务器。
3、TCP 连接管理
使用 TcpClient
和 NetworkStream
建立与服务器的连接,并实现以下功能:
4、错误处理与资源管理
四、应用场景
该解决方案适用于多种工业及物联网场景,包括但不限于:
1、工业自动化:PLC、传感器数据远程采集;
2、物联网设备管理:边缘设备数据集中上传;
3、零售系统:条码扫描枪数据实时上传;
4、医疗设备:仪器数据远程监控;
5、仓储物流:RFID 读写器数据同步。
五、配置说明
根据实际部署环境,需修改以下配置参数:
private static string _serverIp = "192.168.1.100"; // 服务器IP
private static int _serverPort = 8080; // 服务器端口
private static string _portName = "COM1"; // 串口名称
private static int _baudRate = 9600; // 波特率
总结
本文详细讲解了如何使用 C# 实现串口监听与 TCP 转发功能。该方案结构清晰、功能完整,具备良好的稳定性和可扩展性。你可以直接使用本示例作为基础模块,也可以根据具体业务需求进行定制开发。
对于需要远程采集串口设备数据的应用场景,该程序提供了一个轻量但高效的解决方案。无论是工业现场设备监控,还是物联网终端数据上传,都能从中受益。
关键词
C#、#串口通信、#SerialPort、#TCP转发、DataReceived事件、TcpClient、NetworkStream、自动重连、错误处理、资源释放、#工业自动化、#物联网、#远程监控、#条码扫描枪、#RFID读卡器、#传感器数据采集、#数据上传、#嵌入式系统通信、#Socket编程、数据转发服务
如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。如果有任何疑问或需要进一步的帮助,欢迎随时留言。也可以加入微信公众号[DotNet技术匠] 社区,与其他热爱技术的同行一起交流心得,共同成长!作者:技术老小子
出处:mp.weixin.qq.com/s/s8DYBrQGcsP3YEIARJ9rFg声明:网络内容,仅供学习,尊重版权,侵权速删,歉意致谢!
该文章在 2025/7/7 11:34:39 编辑过