C#基于TCP/IP实现接收并推送数据的小工具
作者:对号东
一、前言:基于.NET C#的「数据打通」小帮手
做物联网设备联调、服务端数据采集时,是不是总遇到这些需求:
- 用 C# 快速搭建 TCP服务器端、客户端,和设备 / 服务器建立稳定连接
- 实时接收 TCP 数据流,自动推送到业务 API 接口
- 断连自动重试、推送失败重发,还得有清晰日志方便排查
作为.NET 开发者,之前用 Python 写过类似工具,但项目需要 C# 版本,索性重新造个轮子~ 这个工具轻量无依赖,兼顾「连接稳定性测试」和「数据自动转发」,今天把完整思路 + 代码拆解分享,新手也能直接复用!
当然如果您是需要找一个现成的工具放在windows10/11下直接使用,也可以略过源码研究,直接拿走发行版本使用即可。
功能预览:

二、核心功能 & 技术栈
先明确工具定位,避免功能冗余:
- TCP 客户端:支持配置 IP / 端口,断连自动重试(无需手动重启)
- 数据接收:实时监听 TCP 流,处理粘包 / 半包(自定义解析规则)
- API 推送:异步推送数据到目标接口,支持超时设置、失败重试
- 日志记录:记录连接状态、数据收发、API 推送结果(基于.NET 自带日志)
技术栈(纯.NET 原生,无需第三方依赖):
开发语言:C# (兼容.NET Core 3.1/.>NET4+/NET 5+/.NET 6+)
核心类库:
- System.Net.Sockets(TCP 连接与数据收发)
- System.Net.HttpWebRequest(API 请求)
三、核心代码拆解(带详细注释)
下面分模块讲解,完整代码可直接拉到文末获取,复制就能运行~
1. 核心服务器端工具类-TcpServerTool
负责执行TCP数据接收,并调用API接口地址将收到的数据进行推送。持续接收数据,处理断连重试和粘包问题。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading;
using System.IO;
namespace JoTcp
{
internal class TcpServerTool
{
#region 事件委托
/// <summary>
/// 执行操作消息变更
/// </summary>
public event EventHandler<string> ExecuteMessageChanged;
/// <summary>
/// 客户端个数变更
/// </summary>
public event EventHandler<string> ClientCountChanged;
#endregion
#region 字段、属性
private string _ip = "127.0.0.1"; //ip
private int _port = 9000; //端口
private string _ipPort = "127.0.0.1:9000"; //
private string _api = ""; //api接口地址
private bool _isConnected = false; //是否连接
private bool _isListened = false; //是否侦听
private NetworkStream _stream; //网络基础流
private Socket _serverSocket; //服务端套接字对象
private Thread listenThread = null; //侦听线程
private List<string> _clientIpPortList = new List<string>(); //客户端Ip端口集合
private List<Socket> _clientSocketList = new List<Socket>(); //客户端套接字对象集合
private List<Thread> _clientSocketThreadList = new List<Thread>(); //接收线程:接收客户端对象集合
public string IP { get => _ip; set => _ip = value; }
public int Port { get => _port; set => _port = value; }
public string API { get => _api; set => _api = value; }
public bool IsConnected { get => _isConnected; set => _isConnected = value; }
public bool IsListened { get => _isListened; set => _isListened = value; }
public NetworkStream Stream { get => _stream; set => _stream = value; }
public Socket ServerSocket { get => _serverSocket; set => _serverSocket = value; }
public List<string> ClientIpPortList { get => _clientIpPortList; set => _clientIpPortList = value; }
public List<Socket> ClientSocketList { get => _clientSocketList; set => _clientSocketList = value; }
public List<Thread> ClientSocketThreadList { get => _clientSocketThreadList; set => _clientSocketThreadList = value; }
public string IpPort { get => _ipPort; set => _ipPort = value; }
#endregion
#region 构造方法
public TcpServerTool(string ip, int port,string apiUrl)
{
this.IP = ip;
this.Port = port;
this.API = apiUrl;
}
public TcpServerTool(string ip, string port, string apiUrl)
{
this.IP = ip;
if (int.TryParse(port, out int portStr))
{
this.Port = portStr;
}
if(apiUrl!= null)
{
this.API = apiUrl;
}
}
#endregion
/// <summary>
/// 断开连接
/// </summary>
public void Disconnect()
{
//Console.WriteLine("关闭。。。");
try
{
//状态
IsListened = false;
IsConnected = false;
//Console.WriteLine("关闭2。。。");
foreach (Thread item in ClientSocketThreadList)
{
item.Abort();
}
//关闭对象集合,清除集合项
foreach (Socket item in ClientSocketList)
{
item.Close();
}
//Console.WriteLine("关闭3。。。");
//关闭流
Stream?.Close();
Stream = null;
ServerSocket?.Close();
ServerSocket = null;
ClientSocketThreadList?.Clear();
ClientSocketList?.Clear();
ClientIpPortList?.Clear();
//关闭线程
listenThread?.Abort();
listenThread = null;
//Console.WriteLine("关闭4。。。");
}
catch (Exception ex)
{
ExecuteMessageChanged?.Invoke(this, $"失败....");
ExecuteMessageChanged?.Invoke(this, $"{ex.Message}");
}
}
/// <summary>
/// 服务端打开
/// </summary>
public void Open()
{
try
{
IPAddress ipAddress = IPAddress.Parse(IP); //IP地址
// 创建一个新的 Socket 对象,指定为 IPv4、面向流的(TCP)协议
ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//允许套接字复用
ServerSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
// 服务器绑定指定终端(IP,Port)
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, Port);//创建终端
ServerSocket.Bind(localEndPoint); //绑定终端
ExecuteMessageChanged?.Invoke(this, $"开始侦听准备...");
ServerSocket.Listen(10);
//创建并使用线程侦听
listenThread = new Thread(OnListenClient);
listenThread.IsBackground = true;
listenThread.Start();
IsListened = true;
ExecuteMessageChanged?.Invoke(this, $"本地终端:{ServerSocket.LocalEndPoint}");
ExecuteMessageChanged?.Invoke(this, $"协议:{ServerSocket.LocalEndPoint.AddressFamily}");
ExecuteMessageChanged?.Invoke(this, $"准备完成,开始侦听客户端连接...");
}
catch (Exception ex)
{
ExecuteMessageChanged?.Invoke(this, $"创建连接失败....");
ExecuteMessageChanged?.Invoke(this, $"{ex.Message}");
}
}
/// <summary>
/// 侦听客户端
/// </summary>
public void OnListenClient()
{
try
{
while (true)
{
//接受一个客户端的连接请求
Socket socket = ServerSocket.Accept();
ExecuteMessageChanged?.Invoke(this, $"收到来自【{socket.LocalEndPoint}】远程终端的连接请求...");
// 发送消息给客户端
string sendTestData = "JoTCP Connect...";
ExecuteMessageChanged?.Invoke(this, $"尝试发送数据:{sendTestData}");
Send(socket, sendTestData);
//创建接收数据线程
Thread thread = new Thread(Received);
thread.Name = (ClientSocketThreadList.Count + 1) + "";
thread.IsBackground = true;
thread.Start(socket);
//添加对象到集合
ClientIpPortList.Add(socket.RemoteEndPoint.ToString()); //添加远程终端到集合
ClientSocketList.Add(socket); //添加Socket对现象到集合
ClientSocketThreadList.Add(thread); //创建对应的客户端Socket线程对象并添加到集合
//触发客户端个数变更事件
ClientCountChanged?.Invoke("Add", socket.RemoteEndPoint.ToString());
}
}
catch (Exception ex)
{
ExecuteMessageChanged?.Invoke(this, $"侦听异常:{ex.Message}");
}
}
/// <summary>
/// 接收数据方法
/// </summary>
public void Received(object socketClientPara)
{
Socket socketServer = socketClientPara as Socket;
string remoteEndPoint = socketServer.RemoteEndPoint.ToString(); ;
while (true)
{
try
{
// 读取客户端发送的数据
byte[] buffer = new byte[1024 * 1024];
if (socketServer == null) break;
// 接收客户端发来的数据
int dataLength = socketServer.Receive(buffer);
// 将接收的数据转换为字符串并输出
//string dataReceived = Encoding.ASCII.GetString(buffer, 0, dataLength);
string dataReceived = Encoding.UTF8.GetString(buffer, 0, dataLength).Trim();
ExecuteMessageChanged.Invoke(this, "接收数据:");
ExecuteMessageChanged.Invoke(this, $"{socketServer.RemoteEndPoint}->{dataReceived}");
log("接收数据:" + dataReceived);
// 推送数据至api接口
if (this.API != null && this.API!="")
{
SendApiData(this.API, dataReceived);
}
}
catch (Exception ex)
{
if (IsListened)
{
ClientIpPortList.Remove(remoteEndPoint);
ClientCountChanged?.Invoke("Remove", remoteEndPoint);
Stream = null;
ExecuteMessageChanged.Invoke(this, "客户端已断开连接!");
ExecuteMessageChanged.Invoke(this, $"接收异常:{ex.Message}");
ClientSocketList.Find(s => s.RemoteEndPoint.Equals(remoteEndPoint))?.Close();
ClientSocketList.Remove(socketServer);
break;
}
}
}
}
/// <summary>
/// 发送数据:根据指定IpPort,
/// </summary>
public void Send(string ipPort, string data)
{
try
{
if (IsListened)
{
string socketIpPort = ClientIpPortList.Find(s => s.Equals(ipPort));
Socket socket = ClientSocketList.Find(s => s.RemoteEndPoint.ToString().Equals(ipPort));
if (socket != null)
{
Stream = new NetworkStream(socket);
string dataToSend = data;
byte[] dataBytes = Encoding.UTF8.GetBytes(dataToSend);
Stream.Write(dataBytes, 0, dataBytes.Length);
ExecuteMessageChanged?.Invoke(this, $"发送数据长度:{dataBytes.Length}");
}
else
{
ExecuteMessageChanged?.Invoke(this, $"发送失败!socket = null");
}
}
}
catch (Exception ex)
{
ExecuteMessageChanged?.Invoke(this, $"发送异常:{ex.Message}");
}
}
/// <summary>
/// 发送数据:根据指定Socket对象
/// </summary>
public void Send(Socket socket, string data)
{
try
{
if (IsListened)
{
if (Stream != null)
{
string dataToSend = data;
byte[] dataBytes = Encoding.UTF8.GetBytes(dataToSend);
Stream.Write(dataBytes, 0, dataBytes.Length);
ExecuteMessageChanged?.Invoke(this, $"发送数据长度:{dataBytes.Length}");
}
else
{
Stream = new NetworkStream(socket);
string dataToSend = data;
byte[] dataBytes = Encoding.UTF8.GetBytes(dataToSend);
Stream.Write(dataBytes, 0, dataBytes.Length);
ExecuteMessageChanged?.Invoke(this, $"发送数据长度:{dataBytes.Length}");
}
}
}
catch (Exception ex)
{
ExecuteMessageChanged?.Invoke(this, $"发送异常:{ex.Message}");
}
}
/// <summary>
/// 群发数据:发送数据到所有在连接客户端。
/// </summary>
/// <param name="data"></param>
public void SendGroup(string data)
{
try
{
if (IsListened)
{
foreach (Socket socket in ClientSocketList)
{
Stream = new NetworkStream(socket);
string dataToSend = data;
byte[] dataBytes = Encoding.UTF8.GetBytes(dataToSend);
Stream.Write(dataBytes, 0, dataBytes.Length);
ExecuteMessageChanged.Invoke(this, $"发送到终端:{socket.RemoteEndPoint}");
ExecuteMessageChanged.Invoke(this, $"协议版本:{socket.RemoteEndPoint.AddressFamily}");
ExecuteMessageChanged.Invoke(this, $"发送数据长度:{dataBytes.Length}");
}
}
}
catch (Exception ex)
{
ExecuteMessageChanged.Invoke(this, $"发送异常:{ex.Message}");
}
}
/// <summary>
/// 推送数据到接口
/// </summary>
/// <param name="data"></param>
public void SendApiData(string apiUrl, string data)
{
try
{
//调用接口
String url = apiUrl + "?data=" + Uri.EscapeDataString(data);
log("推送至:" + url);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "GET"; // 设置请求方法为GET
request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"; // 设置接受的内容类型,可选
request.ContentType = "application/x-www-form-urlencoded"; // 如果需要发送数据,设置ContentType,此处为GET请求通常不需要设置ContentType,除非有特殊需求
request.Headers.Add("Accept-Charset", "UTF-8"); // 指定请求内容应该使用UTF-8编码
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
if (response.StatusCode == HttpStatusCode.OK)
{
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
string responseBody = reader.ReadToEnd();
//返回信息
log("推送结果:"+responseBody);
//MessageBox.Show(responseBody);
}
}
}
}
catch (WebException e)
{
//MessageBox.Show($"Error fetching data: {e.Message}");
}
}
// 日志
public void log(string msg)
{
string logFilePath = "log/" + DateTime.Now.ToString("yyyy-MM-dd") + ".txt"; // 日志文件路径
string logMessage = DateTime.Now.ToString() + ": " + msg +"\n"; // 日志内容
File.AppendAllText(logFilePath, logMessage);
}
}
}
2. 模拟TCP/IP客户端工具类-TcpClient
用于实现TCP客户端模拟测试:
using System;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading;
namespace JoTcp
{
public class TcpClientTool
{
#region 字段、属性
private string _ip = "127.0.0.1"; //ip
private int _port = 8000; //端口
private string _ipPort = "127.0.0.1:8000"; //ip端口
private bool _isConnected = false; //是否连接
private Socket _clientSocket; //套接字
private Thread receiveThread = null;
public string IP { get => _ip; set => _ip = value; }
public int Port { get => _port; set => _port = value; }
public string IpPort { get => _ipPort; set => _ipPort = value; }
public bool IsConnected { get => _isConnected; set => _isConnected = value; }
public Socket ClientSocket { get => _clientSocket; set => _clientSocket = value; }
#endregion
#region 事件委托
/// <summary>
/// 执行(操作)消息变更
/// </summary>
public event EventHandler<string> ExecuteMessageChanged;
#endregion
/// <summary>
/// 构造函数
/// </summary>
public TcpClientTool(string ip, string port)
{
this.IP = ip;
if (int.TryParse(port, out int portStr))
{
this.Port = portStr;
}
}
/// <summary>
/// 连接
/// </summary>
public void Connect()
{
try
{
//创建套字节对象(IP4寻址协议,流式连接,TCP协议)
ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//设置终端IpPort
IPAddress ipaddress = IPAddress.Parse(this.IP);
IPEndPoint endpoint = new IPEndPoint(ipaddress, Port);
//连接
ClientSocket.Connect(endpoint);
IsConnected = true;
ExecuteMessageChanged.Invoke(this, $"连接成功!");
Send("A you ok?");
//接收线程
receiveThread = new Thread(Received);
receiveThread.IsBackground = true;
receiveThread.Start();
}
catch (Exception ex)
{
receiveThread?.Abort();
receiveThread = null;
ClientSocket.Close();
IsConnected = false;
ExecuteMessageChanged.Invoke(this, $"连接失败!{ex.Message}");
}
}
/// <summary>
/// 断开连接
/// </summary>
public void Disconnect()
{
ClientSocket.Close();
receiveThread?.Abort();
receiveThread = null;
IsConnected = false;
ExecuteMessageChanged.Invoke(this, $"断开连接!");
}
/// <summary>
/// 发送
/// </summary>
public void Send(string data)
{
try
{
byte[] arrClientSendMsg = Encoding.UTF8.GetBytes(data);
//调用客户端套接字发送字节数组// 发送消息到服务器
ClientSocket.Send(arrClientSendMsg);
ExecuteMessageChanged.Invoke(this, data);
}
catch (Exception ex)
{
ExecuteMessageChanged.Invoke(this, $"发送失败:{ex.Message}");
}
}
/// <summary>
/// 接收
/// </summary>
public void Received()
{
try
{
while (true)
{
//定义一个1M的内存缓冲区 用于临时性存储接收到的信息
byte[] arrRecMsg = new byte[1024 * 1024];
//将客户端套接字接收到的数据存入内存缓冲区, 并获取其长度
int length = ClientSocket.Receive(arrRecMsg);
//将套接字获取到的字节数组转换为人可以看懂的字符串
string strRecMsg = Encoding.UTF8.GetString(arrRecMsg, 0, length);
//将发送的信息追加到聊天内容文本框中
ExecuteMessageChanged.Invoke(this, $"{ClientSocket.RemoteEndPoint}->:{strRecMsg}");
}
}
catch (Exception ex)
{
ExecuteMessageChanged.Invoke(this, $"远程服务器已中断连接...{ex.Message}");
}
}
}
}
3. INI简易配置管理工具类-JoTcp
负责执行config.ini配置文件编辑:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace JoTcp
{
// 单层简单ini读取
internal class JoIniConfig
{
private IniFile iniFile;
public JoIniConfig(string filename="config.ini")
{
//string basePath = System.IO.Directory.GetCurrentDirectory(); // 当前工作目录
//string fullPath = System.IO.Path.Combine(basePath, filename); // 构建完整路径
iniFile = new IniFile(filename);
}
public string Get(string key)
{
return iniFile.GetValue(key);
}
public void Set( string key, string value)
{
iniFile.SetValue(key, value);
}
public void Save()
{
iniFile.Save();
}
}
/// <summary>
/// 纯C#实现的单层INI配置文件读写工具(无节[Section],仅键值对)
/// </summary>
public class IniFile
{
private readonly string _filePath;
private Dictionary<string, string> _keyValues;
/// <summary>
/// 初始化INI文件操作类
/// </summary>
/// <param name="filePath">INI文件路径</param>
public IniFile(string filePath)
{
_filePath = filePath;
_keyValues = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); // 忽略键的大小写
Load(); // 加载文件内容
}
/// <summary>
/// 从文件加载配置
/// </summary>
private void Load()
{
if (!File.Exists(_filePath))
{
_keyValues.Clear();
return;
}
// 读取所有行并解析
var lines = File.ReadAllLines(_filePath);
foreach (var line in lines)
{
string trimmedLine = line.Trim();
// 跳过空行和注释(;或#开头)
if (string.IsNullOrEmpty(trimmedLine) || trimmedLine.StartsWith(";") || trimmedLine.StartsWith("#"))
continue;
// 分割键值对(取第一个=作为分隔符)
int eqIndex = trimmedLine.IndexOf('=');
if (eqIndex <= 0)
continue; // 无效格式(无键或无=)
string key = trimmedLine.Substring(0, eqIndex).Trim();
string value = trimmedLine.Substring(eqIndex + 1).Trim();
if (!string.IsNullOrEmpty(key))
{
_keyValues[key] = value; // 覆盖已有键
}
}
}
/// <summary>
/// 保存配置到文件
/// </summary>
public void Save()
{
// 确保目录存在
string directory = Path.GetDirectoryName(_filePath);
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
// 写入所有键值对
var lines = _keyValues.Select(kv => $"{kv.Key}={kv.Value}").ToList();
File.WriteAllLines(_filePath, lines);
}
/// <summary>
/// 读取指定键的值
/// </summary>
/// <param name="key">键名</param>
/// <param name="defaultValue">默认值(键不存在时返回)</param>
/// <returns>键对应的值</returns>
public string GetValue(string key, string defaultValue = "")
{
return _keyValues.TryGetValue(key, out string value) ? value : defaultValue;
}
/// <summary>
/// 写入键值对(若键已存在则覆盖)
/// </summary>
/// <param name="key">键名</param>
/// <param name="value">值</param>
public void SetValue(string key, string value)
{
if (string.IsNullOrWhiteSpace(key))
throw new ArgumentException("键名不能为空", nameof(key));
_keyValues[key] = value ?? string.Empty; // 处理null值
}
/// <summary>
/// 删除指定键
/// </summary>
/// <param name="key">键名</param>
/// <returns>是否删除成功(键存在则返回true)</returns>
public bool DeleteKey(string key)
{
return _keyValues.Remove(key);
}
/// <summary>
/// 检查键是否存在
/// </summary>
/// <param name="key">键名</param>
/// <returns>是否存在</returns>
public bool ContainsKey(string key)
{
return _keyValues.ContainsKey(key);
}
/// <summary>
/// 获取所有键值对
/// </summary>
/// <returns>键值对字典</returns>
public Dictionary<string, string> GetAllKeys()
{
return new Dictionary<string, string>(_keyValues); // 返回副本,避免外部修改
}
}
}
4. 推送服务端窗口模块-Frm_TcpServer
程序服务执行窗口界面,服务核心程序运行界面:
using System;
using System.Configuration;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace JoTcp
{
public partial class Frm_TcpServer : Form
{
TcpServerTool tcpServerTool;
JoIniConfig config = new JoIniConfig();
public Frm_TcpServer()
{
InitializeComponent();
}
#region 窗体:初始化、加载、关闭
private void Frm_TcpServer_Load(object sender, EventArgs e)
{
tbx_IpAddress.Text = config.Get("ip");
tbx_Port.Text = config.Get("port");
tbx_apiUrl.Text = config.Get("apiurl");
ControlStyleUpdata(picBox_ConnectStatu, Color.Gray);
}
private void Frm_TcpServer_FormClosing(object sender, FormClosingEventArgs e)
{
if (tcpServerTool != null)
{
tcpServerTool.Disconnect();
}
}
#endregion
#region 控件圆角方法
public void ControlStyleUpdata(Control control)
{
GraphicsPath gp = new GraphicsPath();
gp.AddEllipse(control.ClientRectangle);
Region region = new Region(gp);
control.Region = region;
gp.Dispose();
region.Dispose();
}
public void ControlStyleUpdata(Control control, Color bcColor)
{
control.BackColor = bcColor;
ControlStyleUpdata(control);
}
#endregion
#region 鼠标单击事件
private void btn_Open_Click(object sender, EventArgs e)
{
bool isOpen = btn_Open.Text.Equals("打开") ? true : false;
if (isOpen)
{
tcpServerTool = new TcpServerTool(tbx_IpAddress.Text, tbx_Port.Text, tbx_apiUrl.Text);
tcpServerTool.ExecuteMessageChanged += TcpTool_ExecuteMessageChangedCallback;
tcpServerTool.ClientCountChanged += TcpTool_OnCountChangedCallback;
tcpServerTool.Open();
}
else
{
tcpServerTool.Disconnect();
}
//设置显示灯状态
if (tcpServerTool.IsListened) picBox_ConnectStatu.BackColor = Color.LimeGreen;
else picBox_ConnectStatu.BackColor = Color.Gray;
btn_Open.Text = tcpServerTool.IsListened ? "关闭" : "打开";
}
private void btn_Send_Click(object sender, EventArgs e)
{
if (tcpServerTool != null)
{
if (checkBox_SendGroup.Checked)
{
tcpServerTool.SendGroup(rtbx_SendData.Text);
}
else
{
tcpServerTool.Send(cbx_ClientList.Text, rtbx_SendData.Text);
}
}
}
private void btn_ClearReceiveData_Click(object sender, EventArgs e)
{
rtbx_ReceiveData.Text = string.Empty;
}
private void btn_ClearSendData_Click(object sender, EventArgs e)
{
rtbx_SendData.Text = string.Empty;
}
#endregion
/// <summary>
/// 执行(操作)消息
/// </summary>
private void TcpTool_ExecuteMessageChangedCallback(object sender, string message)
{
MessageShow(message);
}
/// <summary>
/// 客户端数量变更事件:
/// 参数1:执行模式(Add,Remove)
/// 参数2:终端(IpPort)
/// </summary>
public void TcpTool_OnCountChangedCallback(object sender, string endPoint)
{
MessageShow($"{sender}:{endPoint}");
ClientListUpdata(endPoint, sender.ToString());
}
/// <summary>
/// 显示消息到文本控件
/// </summary>
public void MessageShow(string data)
{
rtbx_ReceiveData.Invoke(new Action(() =>
{
rtbx_ReceiveData.AppendText($"{DateTime.Now}】{data}{System.Environment.NewLine}");
}));
}
/// <summary>
/// 客户端列表更新
/// </summary>
public void ClientListUpdata(string endPoint, string mode)
{
cbx_ClientList.Invoke(new Action(() =>
{
switch (mode.ToString().ToLower())
{
case "add":
cbx_ClientList.Items.Add(endPoint);
break;
case "remove":
cbx_ClientList.Items.Remove(endPoint);
break;
default:
break;
}
if (cbx_ClientList.Items.Count == 1) cbx_ClientList.SelectedIndex = 0;
if (cbx_ClientList.Items.Count == 0) cbx_ClientList.Text = string.Empty;
}));
}
private void btn_save_Click(object sender, EventArgs e)
{
config.Set("ip", tbx_IpAddress.Text);
config.Set("port", tbx_Port.Text);
config.Set("apiurl", tbx_apiUrl.Text);
config.Save();
MessageBox.Show("当前设置已保存为默认,下次打开直接可用。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
// 获取appsetting
public string configGet(string keyName)
{
//返回配置文件中键为keyName的项的值
return ConfigurationManager.AppSettings[keyName];
}
// 修改、新增、设置 appsetting
public void configSet(string keyName, string newKeyValue)
{
//修改配置文件中键为keyName的项的值
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
config.AppSettings.Settings[keyName].Value = newKeyValue;
config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("appSettings");
}
}
}
4. 模拟客户端窗口模块-Frm_TcpClient
模拟客户端执行窗口界面:
using JoTcp;
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace JoTcp
{
public partial class Frm_TcpClient : Form
{
TcpClientTool tcpTool;
JoIniConfig config = new JoIniConfig();
#region 窗体:初始化、加载、关闭
public Frm_TcpClient()
{
InitializeComponent();
}
private void Frm_TcpClient_Load(object sender, EventArgs e)
{
tbx_IpAddress.Text = config.Get("ip");
tbx_Port.Text = config.Get("port");
ControlStyleUpdata(picBox_ConnectStatu, Color.Gray);
}
private void Frm_TcpClient_FormClosing(object sender, FormClosingEventArgs e)
{
tcpTool?.Disconnect();
tcpTool = null;
}
#endregion
#region 鼠标单击事件
private void btn_Connect_Click(object sender, EventArgs e)
{
bool isOpen = btn_Connect.Text.Equals("连接") ? true : false;
if (isOpen)
{
tcpTool = new TcpClientTool(tbx_IpAddress.Text, tbx_Port.Text);
tcpTool.ExecuteMessageChanged += TcpTool_ExecuteMessageCallBack;
tcpTool.Connect();
}
else
{
tcpTool.Disconnect();
}
if (tcpTool.IsConnected) picBox_ConnectStatu.BackColor = Color.LimeGreen;
else picBox_ConnectStatu.BackColor = Color.Gray;
btn_Connect.Text = tcpTool.IsConnected ? "断开" : "连接";
}
private void btn_Send_Click(object sender, EventArgs e)
{
if (tcpTool != null)
{
tcpTool.Send(rtbx_SendData.Text);
}
}
private void btn_ClearReceiveData_Click(object sender, EventArgs e)
{
rtbx_ReceiveData.Text = string.Empty;
}
private void btn_ClearSendData_Click(object sender, EventArgs e)
{
rtbx_SendData.Text = string.Empty;
}
#endregion
#region 控件圆角方法
/// <summary>
/// 控件样式更新
/// </summary>
public void ControlStyleUpdata(Control control)
{
GraphicsPath gp = new GraphicsPath();
gp.AddEllipse(control.ClientRectangle);
Region region = new Region(gp);
control.Region = region;
gp.Dispose();
region.Dispose();
}
/// <summary>
/// 控件样式更新
/// </summary>
public void ControlStyleUpdata(Control control, Color bcColor)
{
control.BackColor = bcColor;
ControlStyleUpdata(control);
}
#endregion
/// <summary>
/// 操作消息更新
/// </summary>
private void TcpTool_ExecuteMessageCallBack(object sender, string e)
{
MessageShow(e);
}
/// <summary>
/// 消息显示到控件
/// </summary>
public void MessageShow(string data)
{
rtbx_ReceiveData.Invoke(new Action(() =>
{
rtbx_ReceiveData.AppendText($"{DateTime.Now}】{data}{System.Environment.NewLine}");
}));
}
}
}5. 主窗口模块-MainForm
功能聚合主窗口界面:
using System;
using System.IO;
using System.Windows.Forms;
namespace JoTcp
{
public partial class MainForm : Form
{
Frm_TcpClient tcpClient;
Frm_TcpServer tcpServer;
public MainForm()
{
InitializeComponent();
this.MinimumSize = new System.Drawing.Size(820, 745);
this.Size = new System.Drawing.Size(820, 745);
//1197, 189
}
/// <summary>
/// 点击服务端按钮,显示服务端
/// </summary>
private void btn_TCPServer_Click(object sender, EventArgs e)
{
if (tcpServer == null)
{
tcpServer = new Frm_TcpServer();
}
panel_Container.Controls.Clear();//移除所有控件
tcpServer.TopLevel = false;
tcpServer.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
panel_Container.Width = tcpServer.Width;
tcpServer.Dock = DockStyle.Fill;
panel_Container.Controls.Add(tcpServer);
tcpServer.Show();
}
/// <summary>
/// 点击客户端按钮,显示客户端
/// </summary>
private void btn_TCPClient_Click(object sender, EventArgs e)
{
if (tcpClient == null)
{
tcpClient = new Frm_TcpClient();
}
panel_Container.Controls.Clear();//移除所有控件
tcpClient.TopLevel = false;
tcpClient.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
panel_Container.Width = tcpClient.Width;
tcpClient.Dock = DockStyle.Fill;
panel_Container.Controls.Add(tcpClient);
tcpClient.Show();
}
/// <summary>
/// 窗体加载时,显示服务端
/// </summary>
private void MainForm_Load(object sender, EventArgs e)
{
if (tcpServer == null)
{
tcpServer = new Frm_TcpServer();
}
panel_Container.Controls.Clear();//移除所有控件
tcpServer.TopLevel = false;
tcpServer.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
panel_Container.Width = tcpServer.Width;
tcpServer.Dock = DockStyle.Fill;
panel_Container.Controls.Add(tcpServer);
tcpServer.Show();
// 日志目录创建
String directoryPath = "log";
if (!Directory.Exists(directoryPath))
{
Directory.CreateDirectory(directoryPath);
//Console.WriteLine("目录已创建: " + directoryPath);
}
else
{
//Console.WriteLine("目录已存在: " + directoryPath);
}
}
/// <summary>
/// 窗体关闭,关闭服务端、客户端
/// </summary>
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
tcpClient?.Close();
tcpServer?.Close();
}
private void server_btn_Click(object sender, EventArgs e)
{
if (tcpServer == null)
{
tcpServer = new Frm_TcpServer();
}
panel_Container.Controls.Clear();//移除所有控件
tcpServer.TopLevel = false;
tcpServer.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
panel_Container.Width = tcpServer.Width;
tcpServer.Dock = DockStyle.Fill;
panel_Container.Controls.Add(tcpServer);
tcpServer.Show();
}
private void client_btn_Click(object sender, EventArgs e)
{
if (tcpClient == null)
{
tcpClient = new Frm_TcpClient();
}
panel_Container.Controls.Clear();//移除所有控件
tcpClient.TopLevel = false;
tcpClient.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
panel_Container.Width = tcpClient.Width;
tcpClient.Dock = DockStyle.Fill;
panel_Container.Controls.Add(tcpClient);
tcpClient.Show();
}
private void ServerToolStripMenuItem_Click(object sender, EventArgs e)
{
labelTitle.Text = "接推服务端";
if (tcpServer == null)
{
tcpServer = new Frm_TcpServer();
}
panel_Container.Controls.Clear();//移除所有控件
tcpServer.TopLevel = false;
tcpServer.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
panel_Container.Width = tcpServer.Width;
tcpServer.Dock = DockStyle.Fill;
panel_Container.Controls.Add(tcpServer);
tcpServer.Show();
}
private void ClientToolStripMenuItem_Click(object sender, EventArgs e)
{
labelTitle.Text = "模拟客户端";
if (tcpClient == null)
{
tcpClient = new Frm_TcpClient();
}
panel_Container.Controls.Clear();//移除所有控件
tcpClient.TopLevel = false;
tcpClient.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
panel_Container.Width = tcpClient.Width;
tcpClient.Dock = DockStyle.Fill;
panel_Container.Controls.Add(tcpClient);
tcpClient.Show();
}
private void AboutToolStripMenuItem_Click(object sender, EventArgs e)
{
Frm_about dialog = new Frm_about(); //
dialog.ShowDialog(); // 使用ShowDialog()方法显示对话框,这会阻止代码继续执行直到对话框关闭
}
}
}6. 入库主程序-Program
using System;
using System.Windows.Forms;
namespace JoTcp
{
internal static class Program
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
}
}
四、关于配置文件
本程序采用了自定义的INI单层配置方案,在config.ini中直接配置以下参数:
## 配置 ip=127.0.0.1 port=9001 apiurl=https://api.2om.cn/ceshi
五、使用场景 & 实测效果
物联网设备测试:和 PLC、传感器建立 TCP 连接,实时接收设备数据并推送到云平台,验证设备稳定性。
服务端日志转发:接收 Windows/Linux 服务器的 TCP 日志流,推送到 ELK 等日志分析平台,无需手动采集。
.NET 项目数据上报:本地.NET 程序生成的数据通过 TCP 发送,工具自动转发到业务 API,简化项目开发。
实测效果(.NET 4.7 + Windows 10):
- 数据处理能力:每秒 150 + 条 TCP 数据,API 推送无阻塞
- 重连稳定性:断网后 5 秒自动重连,恢复后无缝续传
- 推送可靠性:API 临时不可用时,重试 3 次后仍失败会记录日志,避免数据丢失
到此这篇关于C#基于TCP/IP实现接收并推送数据的小工具的文章就介绍到这了,更多相关C#数据接收与推送内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
