C#TCP通讯封装服务器工具类
C#TCP通讯封装服务器工具类
- 1使用说明
- 2封装
1使用说明
- 添加接受数据回调函数事件
方式1:通过有参构造函数添加
方式2:调用:public EventHandler<byte[]> AddEventToDataReceived
- 添加输出日志回调函数事件
方式1:通过有参构造函数添加
方式2:调用:public Action<EMessage, IPEndPoint, int, string> AddEventToOutLog
- 监听客户端发送数据线程和向其他客户端转发消息的数据如何输出日志信息
方式:设置属性【OutputReceivedLog 】、设置属性【OutputReplyLog】
类型:Null :不输出
Length:仅输出接受数据的长度信息
UTF8:UTF8-解析输出
ASCII:ASCII-解析输出
ByteToString:输出字节的字符串形式
2封装
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Tcp_Server
{
public class ServerModel
{
private bool _firstStartServer = true;
private TcpListener _server;
private List<TcpClient> _tcpClientsList = new List<TcpClient>();
/// <summary>
/// 接受消息回调函数
/// </summary>
private EventHandler<byte[]> _callbackEventDataReceived;
/// <summary>
/// 日志信息回调函数
/// int:线程ID
/// </summary>
private Action<EMessage, IPEndPoint, int, string> _callbackEventOutLog;
public ServerModel(EventHandler<byte[]> callbackEventDataReceived, Action<EMessage, IPEndPoint, int, string> callbackEventOutLog)
{
AddEventToDataReceived = callbackEventDataReceived;
AddEventToOutLog = callbackEventOutLog;
}
public ServerModel()
{
}
~ServerModel()
{
CloseServer();
}
/// <summary>
/// 监听接入客户端
/// </summary>
private void ListeningClient()
{
TcpClient client = null;
try
{
//等待客户端连接
client = _server.AcceptTcpClient();
AddLog(client, EMessage.State, "已连接");
//为(每个)客户端创建线程处理通信
new Task(() => HandleClient(client)).Start();
}
catch (Exception ex)
{
AddLog(client, EMessage.Exception, $"ListeningClient: {ex.Message}");
}
}
private void HandleClient(TcpClient client)
{
try
{
NetworkStream stream = client.GetStream();
_tcpClientsList.Add(client);
byte[] buffer = new byte[1024];
while (IsOpen)
{
// 异步读取客户端发送的消息
int bytesRead = stream.Read(buffer, 0, buffer.Length);
if (bytesRead == 0)
{
// 客户端断开连接
break;
}
var receive = new byte[bytesRead];
Array.Copy(buffer, receive, bytesRead);
_callbackEventDataReceived?.Invoke(null, receive);
PacketParseLog(EMessage.Receive, OutputReceivedLog, client, receive);
//转发消息给其他客户端
BroadcastMessage(client, buffer);
}
}
catch (Exception ex)
{
AddLog(client, EMessage.Exception, $"HandleClient: {ex.Message}");
}
}
private void BroadcastMessage(TcpClient sender, byte[] buffer)
{
int length = buffer.Length;
foreach (TcpClient client in _tcpClientsList)
{
if (client != sender && client.Connected)
{
try
{
NetworkStream stream = client.GetStream();
stream.Write(buffer, 0, length);
PacketParseLog(EMessage.Reply, OutputReplyLog, client, buffer);
}
catch (Exception ex)
{
AddLog(client, EMessage.Exception, $"BroadcastMessage: {ex.Message}");
}
}
}
}
/// <summary>
/// 解析数据包输出至日志
/// </summary>
/// <param name="messageType"></param>
/// <param name="type"></param>
/// <param name="client"></param>
/// <param name="bytes"></param>
private void PacketParseLog(EMessage messageType, ETranscoding type, TcpClient client, byte[] bytes)
{
string message;
switch (type)
{
case ETranscoding.Length:
message = bytes.Length.ToString();
break;
case ETranscoding.UTF8:
message = Encoding.UTF8.GetString(bytes);
break;
case ETranscoding.ASCII:
message = Encoding.ASCII.GetString(bytes);
break;
case ETranscoding.ByteToString:
var builder = new StringBuilder();
builder.Append("[ ");
foreach (var b in bytes)
{
builder.Append(Convert.ToString(b, 16).PadLeft(2, '0').ToUpper() + " ");
}
builder.Append("]");
message = builder.ToString();
break;
default:
return;
}
AddLog(client, messageType, message);
}
private void AddLog(TcpClient client, EMessage type, string description)
{
int threadId = Thread.CurrentThread.ManagedThreadId;
IPEndPoint ipEndPoint;
if (client != null)
{
ipEndPoint = (IPEndPoint)client.Client.RemoteEndPoint;
}
else
{
ipEndPoint = (IPEndPoint)_server.LocalEndpoint;
}
_callbackEventOutLog?.Invoke(type, ipEndPoint, threadId, description);
}
/********隔离线********隔离线********隔离线********隔离线********隔离线********隔离线********隔离线********/
public EventHandler<byte[]> AddEventToDataReceived
{
set
{
if (value != null) _callbackEventDataReceived += value;
}
}
public Action<EMessage, IPEndPoint, int, string> AddEventToOutLog
{
set
{
if (value != null) _callbackEventOutLog += value;
}
}
/// <summary>
/// 接受到客户端数据时输出日志信息的方式,默认:不输出
/// </summary>
public ETranscoding OutputReceivedLog { get; set; } = ETranscoding.Null;
/// <summary>
/// 转发消息Log时数据解析方式
/// </summary>
public ETranscoding OutputReplyLog { get; set; } = ETranscoding.Null;
public bool StartServer(string ip, int port)
{
try
{
CloseServer();
//创建一个 TCP 监听器,监听本地 IP 地址和端口
_server = new TcpListener(IPAddress.Parse(ip), port);
// 启动服务器
_server.Start();
AddLog(null, EMessage.State, "服务器已启动");
IsOpen = true;
if (_firstStartServer)
{
_firstStartServer = false;
new Task(() =>
{
while (IsOpen)
{
Thread.Sleep(1000);
ListeningClient();
}
}).Start();
}
}
catch (Exception ex)
{
AddLog(null, EMessage.Exception, $"StartServer: {ex.Message}");
}
return IsOpen;
}
public void CloseServer()
{
if (IsOpen)
{
// 停止服务器
_server.Stop();
}
IsOpen = false;
_server = null;
}
public bool IsOpen { get; private set; }
public enum EMessage
{
[Description("状态信息")]
State = 1,
[Description("发送")]
Send = 3,
[Description("接受")]
Receive = 5,
[Description("异常")]
Exception = 7,
[Description("回复")]
Reply = 9,
}
/// <summary>
/// 接受到客户端数据时字节码解析方式,解析后输出至日志
/// </summary>
public enum ETranscoding
{
/// <summary>
/// 不输出
/// </summary>
Null = 101,
/// <summary>
/// 仅输出接受数据的长度信息
/// </summary>
Length,
/// <summary>
/// UTF8-解析输出
/// </summary>
UTF8,
/// <summary>
/// ASCII-解析输出
/// </summary>
ASCII,
/// <summary>
/// 输出字节的字符串形式
/// </summary>
ByteToString
}
}
}