之前实现的检验虚拟盒子虽然实现了串口转TCP功能,但是缺乏设计,表现为设计太僵硬,只能固定两三种转换模式。而且随着转换增加复杂度太大。比如要实现某些仪器TCP不能跨网站做TCP直接跳板就难度大大增加。
虚拟盒子体现为代码力,这次体现为设计力。
源码
为了解决设计不足导致的扩展困难,全新设计了超级转换器,分享初版代码。这次抽取了转换器接口,和提取了委托。实现为一个dll,方便其他exe快速引入。
拿串口端来说,本质就是1.监控串口发来的消息,然后转发出去。2.把其他端发来的消息推送到串口。
拿tcp端来说,本质就是1.监控tcp端发来的消息,然后转发出去。2.把其他端发来的消息转发给tcp。
默认实现了串口、tcp服务端、tcp客户端、udp服务端、udp客户端。也可以实现接口来实现读写文本,调用webservice等,只要是需要转发消息的都可。
抽取接口如下(所有的消息实现端实现该接口):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MessageSwitch
{
///
/// [功能描述:消息转换器接口,所有消息用户控件实现该接口,符合该接口的实现可以配置到转接中心两端]
/// [创建者:zlz]
/// [创建时间:2021年11月13日]
///<说明>
/// [说明:消息转换器接口,所有消息用户控件实现该接口,符合该接口的实现可以配置到转接中心两端]
///
///<修改记录>
/// [修改时间:本次修改时间]
/// [修改内容:本次修改内容]
///
///<修改记录>
/// [修改时间:本次修改时间]
/// [修改内容:本次修改内容]
///
///
public interface IMessageSwitch
{
///
/// 得到实现类型的名字,供写日志用
///
///
string GetTypeName();
///
/// 得到配置串
///
/// 配置串
string GetConfig();
///
/// 设置配置,供主程序把配置设置上去
///
/// 配置串
/// 是否成功
bool SetConfig(string confStr);
///
/// 供转换中心设置回调方法给消息实现
///
/// 推送器
/// 推送端来源
/// 写日志委托
/// 是否成功
bool SetPushDelegate(PushMessageToSwitch push, SwitchType type, WriteLog log);
///
/// 启动
///
/// 是否成功
bool Start();
///
/// 停止
///
/// 是否成功
bool Stop();
///
/// 提供转换中心给改接口推送消息
///
/// 消息的比特数组
/// 是否成功
bool SendMessage(byte[] msgByteArr);
///
/// 得到该对象的反射配置串,供主程序按配置加载,格式:类全名,动态库名字(不带dll)
///
///
string GetReflectStr();
}
}
转换器及委托实现转换逻辑
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
namespace MessageSwitch
{
///
/// 交换类型,标识消息实现所在的端
///
public enum SwitchType
{
In,
Out
}
///
/// 把收到的消息推送到转换器委托,所有消息接口通过该委托把消息推送到转换中心
///
/// 消息
/// 推送端来源
/// 是否成功
public delegate bool PushMessageToSwitch(byte[] msgByteArr,SwitchType type);
///
/// 写日志委托
///
/// 消息
public delegate void WriteLog(string msg);
///
/// 添加转换器
///
///
public delegate void AddMessageSwitch(IMessageSwitch sw,SwitchType type);
///
/// [功能描述:消息转换器核心,实现消息转换]
/// [创建者:zlz]
/// [创建时间:2021年11月13日]
///<说明>
/// [说明:消息转换器核心,实现消息转换]
///
///<修改记录>
/// [修改时间:本次修改时间]
/// [修改内容:本次修改内容]
///
///<修改记录>
/// [修改时间:本次修改时间]
/// [修改内容:本次修改内容]
///
///
public class SwitchMian
{
///
/// 输入端接口集合
///
private List<IMessageSwitch> inList = new List<IMessageSwitch>();
///
/// 输出端消息集合
///
private List<IMessageSwitch> outList = new List<IMessageSwitch>();
///
/// 推送消息委托
///
private PushMessageToSwitch PushMessage;
///
/// 写日志委托
///
private WriteLog log;
///
/// 构造函数
///
public SwitchMian(WriteLog logW)
{
PushMessage = new PushMessageToSwitch(PushMessageToSwitchDo);
log = logW;
}
///
/// 接收推过来的消息
///
/// 消息
/// 来源
/// 是否成功
private bool PushMessageToSwitchDo(byte[] msgByteArr, SwitchType type)
{
string lineStr = System.Text.Encoding.Default.GetString(msgByteArr);
//处理不可见字符为可见字符
lineStr = Util.DealNotSeeToSeeChar(lineStr);
//消息来自In就给所有Out推送
if (type == SwitchType.In)
{
if (outList != null && outList.Count > 0)
{
foreach (IMessageSwitch s in outList)
{
if (log != null)
{
log("输入->输出"+lineStr);
}
s.SendMessage(msgByteArr);
}
}
}
//消息来自Out就给所有In推送
if (type == SwitchType.Out)
{
if (inList != null && inList.Count > 0)
{
foreach (IMessageSwitch s in inList)
{
if (log != null)
{
log("输出->输入" + lineStr);
}
s.SendMessage(msgByteArr);
}
}
}
return true;
}
///
/// 添加消息实现到输入端
///
/// 消息实现
public void AddToIn(IMessageSwitch obj)
{
if (log != null)
{
log(obj.GetTypeName()+"加入输入端");
}
obj.SetPushDelegate(PushMessage, SwitchType.In,log);
inList.Add(obj);
}
///
/// 添加消息实现到输出端
///
/// 消息实现
public void AddToOut(IMessageSwitch obj)
{
if (log != null)
{
log(obj.GetTypeName() + "加入输出端");
}
obj.SetPushDelegate(PushMessage, SwitchType.Out,log);
outList.Add(obj);
}
///
/// 得到配置
///
/// 配置串
public string GetConfig()
{
List<ConfDto> confList = new List<ConfDto>();
if (inList != null && inList.Count > 0)
{
foreach (IMessageSwitch s in inList)
{
if (log != null)
{
log("获取:" + s.GetTypeName()+"配置");
}
ConfDto dto = new ConfDto();
dto.ConfStr = s.GetConfig();
dto.ReflectStr = s.GetReflectStr();
dto.Type = SwitchType.In;
confList.Add(dto);
}
}
if (outList != null && outList.Count > 0)
{
foreach (IMessageSwitch s in outList)
{
if (log != null)
{
log("获取:" + s.GetTypeName() + "配置");
}
ConfDto dto = new ConfDto();
dto.ConfStr = s.GetConfig();
dto.ReflectStr = s.GetReflectStr();
dto.Type = SwitchType.Out;
confList.Add(dto);
}
}
return Util.Serializer(confList.GetType(), confList);
}
///
/// 设置配置
///
/// 配置串
/// 回调方法
public void LoadConfig(string confStr,AddMessageSwitch addSw)
{
List<ConfDto> confList = Util.XmlDeserialize<List<ConfDto>>(confStr, Encoding.Default);
if (confList != null && confList.Count > 0)
{
foreach (var v in confList)
{
if (v.Type == SwitchType.In)
{
object obj = GetObjectByReflectStr(v.ReflectStr);
if (obj != null)
{
IMessageSwitch swi = obj as IMessageSwitch;
if (swi != null)
{
swi.SetConfig(v.ConfStr);
if (log != null)
{
log("载入:" + swi.GetTypeName() + "对象到输入端");
}
AddToIn(swi);
//执行回调
if (addSw != null)
{
addSw(swi, SwitchType.In);
}
}
}
}
if (v.Type == SwitchType.Out)
{
object obj = GetObjectByReflectStr(v.ReflectStr);
if (obj != null)
{
IMessageSwitch swi = obj as IMessageSwitch;
if (swi != null)
{
swi.SetConfig(v.ConfStr);
if (log != null)
{
log("载入:" + swi.GetTypeName() + "对象到输出端");
}
AddToOut(swi);
//执行回调
if (addSw != null)
{
addSw(swi, SwitchType.Out);
}
}
}
}
}
}
}
///
/// 通过反射串得到对象
///
/// 反射串
///
public object GetObjectByReflectStr(string reflectStr)
{
try
{
if (log != null)
{
log("准备解析处理对象:" + reflectStr);
}
string[] strArr = reflectStr.Replace(" ", "").Split(',');
if (strArr.Length < 2)
{
if (log != null)
{
log("配置的处理对象错误,请采用类全名,动态库名");
}
}
if ((strArr.Length) < 2)
{
return null;
}
string path = System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory,strArr[1]);
if (!path.Contains(".dll"))
{
path = path + ".dll";
}
Assembly assembly = Assembly.LoadFile(path);
object obj = assembly.CreateInstance(strArr[0], false);
if (log != null)
{
log("解析处理对象:" + reflectStr + "成功");
}
return obj;
}
catch (Exception ex)
{
if (log != null)
{
log("解析处理对象出错:" + ex.Message);
}
return null;
}
}
///
/// 开启转换器
///
public void StartSwitch()
{
if (inList != null && inList.Count > 0)
{
foreach (IMessageSwitch s in inList)
{
if (log != null)
{
log("开启输输入端:" + s.GetTypeName());
}
s.Start();
}
}
if (outList != null && outList.Count > 0)
{
foreach (IMessageSwitch s in outList)
{
if (log != null)
{
log("开启输出端:" + s.GetTypeName());
}
s.Start();
}
}
}
///
/// 停止转换器
///
public void StopSwitch()
{
if (inList != null && inList.Count > 0)
{
foreach (IMessageSwitch s in inList)
{
if (log != null)
{
log("停止输输入端:" + s.GetTypeName());
}
s.Stop();
}
}
if (outList != null && outList.Count > 0)
{
foreach (IMessageSwitch s in outList)
{
if (log != null)
{
log("停止输出端:" + s.GetTypeName());
}
s.Stop();
}
}
}
}
///
/// 配置实体
///
public class ConfDto
{
///
/// 反射用的串
///
public string ReflectStr
{
get;
set;
}
///
/// 类型
///
public SwitchType Type
{
get;
set;
}
///
/// 配置串
///
public string ConfStr
{
get;
set;
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace MessageSwitch
{
public partial class SwitchMainUI : UserControl
{
///
/// 转换器主对象
///
private SwitchMian switchMian =null;
///
/// 输入控件顶部
///
private int InTop = 0;
///
/// 输出控件顶部
///
private int OutTop = 0;
public SwitchMainUI()
{
InitializeComponent();
}
///
/// 添加输入端
///
///
///
private void btnAddIn_Click(object sender, EventArgs e)
{
object reflectObj = cmbType.SelectedValue;
if (reflectObj == null)
{
MessageBox.Show("请选择要添加的类型!", "提示");
return;
}
object swiObj = switchMian.GetObjectByReflectStr(reflectObj.ToString());
IMessageSwitch swi = swiObj as IMessageSwitch;
UserControl swiu = swiObj as UserControl;
swiu.Top = InTop;
InTop += swiu.Height+10;
tabPageIn.Controls.Add(swiu);
switchMian.AddToIn(swi);
}
///
/// 添加输出端
///
///
///
private void btnAddOut_Click(object sender, EventArgs e)
{
object reflectObj = cmbType.SelectedValue;
if (reflectObj == null)
{
MessageBox.Show("请选择要添加的类型!", "提示");
return;
}
object swiObj = switchMian.GetObjectByReflectStr(reflectObj.ToString());
IMessageSwitch swi = swiObj as IMessageSwitch;
UserControl swiu = swiObj as UserControl;
swiu.Top = OutTop;
OutTop += swiu.Height+10;
tabPageOut.Controls.Add(swiu);
switchMian.AddToOut(swi);
}
///
/// 保存配置
///
///
///
private void btnSaveConfig_Click(object sender, EventArgs e)
{
string confStr=switchMian.GetConfig();
string path = System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "SwitchMian.conf");
Util.WriteTxt(path, confStr);
MessageBox.Show("配置保存在SwitchMian.conf!", "提示");
}
///
/// 启动转换
///
///
///
private void btnStart_Click(object sender, EventArgs e)
{
switchMian.StartSwitch();
}
///
/// 停止转换
///
///
///
private void btnStop_Click(object sender, EventArgs e)
{
switchMian.StopSwitch();
}
///
/// 加载方法
///
///
///
private void SwitchMainUI_Load(object sender, EventArgs e)
{
switchMian = new SwitchMian(new WriteLog(WritLogs));
string path = System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "SwitchType.conf");
string TypeConfStr = Util.ReadTxt(path);
if (TypeConfStr != "")
{
TypeConfStr = TypeConfStr.Replace("\r\n",(char)0+"");
string[] arr = TypeConfStr.Split((char)0);
List<CmbDto> cmbList = new List<CmbDto>();
foreach(string s in arr)
{
if (s == "")
{
continue;
}
string[] arrOne = s.Split('^');
if (arrOne.Length != 2)
{
MessageBox.Show("配置格式不对!格式:名称^反射串", "提示");
}
else
{
CmbDto dto = new CmbDto();
dto.Name = arrOne[0];
dto.ReflectStr = arrOne[1];
cmbList.Add(dto);
}
}
cmbType.DataSource = cmbList;
cmbType.ValueMember = "ReflectStr";
cmbType.DisplayMember = "Name";
}
string pathConf = System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "SwitchMian.conf");
if(System.IO.File.Exists(pathConf))
{
string conf=Util.ReadTxt(pathConf);
switchMian.LoadConfig(conf, new AddMessageSwitch(AddMessageSwitchDo));
switchMian.StartSwitch();
}
}
///
/// 添加转换器
///
///
public void AddMessageSwitchDo(IMessageSwitch sw,SwitchType type)
{
UserControl swiu = sw as UserControl;
if (type == SwitchType.In)
{
swiu.Top = InTop;
InTop += swiu.Height + 10;
tabPageIn.Controls.Add(swiu);
}
if (type == SwitchType.Out)
{
swiu.Top = OutTop;
OutTop += swiu.Height + 10;
tabPageOut.Controls.Add(swiu);
}
}
///
/// 写日志
///
///
private void WritLogs(string log)
{
object [] para=new object[1];
para[0]=log;
this.Invoke(new WriteLog(WritLogsDo), para);
}
///
/// 写日志
///
///
private void WritLogsDo(string log)
{
txtInfo.Text += DateTime.Now.ToString("HH:mm:ss ")+ log + "\n";
}
///
/// 下拉框实体
///
class CmbDto
{
///
/// 显示名称
///
public string Name
{
get;
set;
}
///
/// 反射串
///
public string ReflectStr
{
get;
set;
}
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
namespace MessageSwitch
{
///
/// [功能描述:串口实现]
/// [创建者:zlz]
/// [创建时间:2021年11月13日]
///<说明>
/// [说明:串口实现]
///
///<修改记录>
/// [修改时间:本次修改时间]
/// [修改内容:本次修改内容]
///
///<修改记录>
/// [修改时间:本次修改时间]
/// [修改内容:本次修改内容]
///
///
public partial class UCSerialPort : UserControl, IMessageSwitch
{
///
/// 串口对象
///
private SerialPort comm = new SerialPort();
///
/// 推送器
///
private PushMessageToSwitch pushToSwitch;
///
/// 类型
///
SwitchType type;
///
/// 写日志委托
///
private WriteLog log;
public UCSerialPort()
{
InitializeComponent();
}
///
/// 得到类型名字
///
///
public string GetTypeName()
{
return "串口";
}
///
/// 得到配置
///
///
public string GetConfig()
{
string confStr = cmbPortName.Text + "#" + cmbBaudrate.Text + "#" + cmbDataBits.Text + "#" + cmbStopBits.Text + "#" + cmbParity.Text;
return confStr;
}
///
/// 设置配置
///
///
///
public bool SetConfig(string confStr)
{
string[] arr = confStr.Split('#');
if (arr.Length != 5)
{
MessageBox.Show("串口配置格式不对!应该是#分隔的5位", "提示");
return false;
}
cmbPortName.Text = arr[0];
cmbBaudrate.Text = arr[1];
cmbDataBits.Text = arr[2];
cmbStopBits.Text = arr[3];
cmbParity.Text = arr[4];
return true;
}
///
/// 设置推送委托
///
/// 推送器
/// 类型
/// 日志委托
///
public bool SetPushDelegate(PushMessageToSwitch push, SwitchType ptype, WriteLog plog)
{
pushToSwitch = push;
type = ptype;
log = plog;
return true;
}
///
/// 启动串口
///
///
public bool Start()
{
//根据当前串口对象,来判断操作
if (comm.IsOpen)
{
//打开时点击,则关闭串口
comm.Close();
}
//关闭时点击,则设置好端口,波特率后打开
comm.PortName = cmbPortName.Text;
comm.BaudRate = int.Parse(cmbBaudrate.Text);
comm.DataBits = int.Parse(cmbDataBits.Text);
//停止位为枚举类型非用户自定义
switch (cmbStopBits.Text)
{
default:
comm.StopBits = StopBits.None;
break;
case "1":
comm.StopBits = StopBits.One;
break;
case "2":
comm.StopBits = StopBits.Two;
break;
case "1.5":
comm.StopBits = StopBits.OnePointFive;
break;
}
//校验位同样非用户自定义
switch (cmbParity.Text)
{
default:
comm.Parity = Parity.None;
break;
case "Odd":
comm.Parity = Parity.Odd;
break;
case "Even":
comm.Parity = Parity.Even;
break;
case "Mark":
comm.Parity = Parity.Mark;
break;
case "Space":
comm.Parity = Parity.Space;
break;
}
try
{
comm.Open();
if (log != null)
{
log("启动:启动串口成功");
statePortName.ForeColor = Color.Blue;
}
}
catch (Exception ex)
{
statePortName.ForeColor = Color.Red;
//捕获到异常信息,创建一个新的comm对象,之前的不能用了。
comm = new SerialPort();
//初始化SerialPort对象
comm.NewLine = "\r\n";
comm.RtsEnable = true;//根据实际情况吧。
//添加事件注册
comm.DataReceived += cmb_DataReceived;
//现实异常信息给客户。
MessageBox.Show(ex.Message, "提示", MessageBoxButtons.OK);
return false;
}
return true;
}
///
/// 停止串口
///
///
public bool Stop()
{
if (comm.IsOpen)
{
comm.Close();
statePortName.ForeColor = Color.Red;
if (log != null)
{
log("停止:串口已关闭");
statePortName.ForeColor = Color.Blue;
}
}
return true;
}
///
/// 给串口发消息
///
///
///
public bool SendMessage(byte[] msgByteArr)
{
//串口打开的话就转给串口
if (comm.IsOpen)
{
//转发给串口
comm.Write(msgByteArr, 0, msgByteArr.Count());
}
else
{
if (log != null)
{
log("串口未打开,无法发送");
statePortName.ForeColor = Color.Blue;
}
}
return true;
}
///
/// 得到反射串
///
///
public string GetReflectStr()
{
return "MessageSwitch.UCSerialPort,MessageSwitch.dll";
}
///
/// 加载函数
///
///
///
private void UCSerialPort_Load(object sender, EventArgs e)
{
//初始化下拉串口名称列表框
string[] ports = SerialPort.GetPortNames();
//没串口提示
if (ports == null || ports.Count() == 0)
{
MessageBox.Show("检测到当前运行电脑没有串口!");
}
Array.Sort(ports);
cmbPortName.Items.AddRange(ports);
//波特率
string[] baudrates = {
"1200", "2400", "4800", "9600", "19200", "38400", "57600", "115200" };
cmbBaudrate.Items.AddRange(baudrates);
//数据位
string[] databits = {
"8", "7", "6", "5", "4" };
cmbDataBits.Items.AddRange(databits);
//停止位
string[] stopbits = {
"1", "1.5", "2" };
cmbStopBits.Items.AddRange(stopbits);
//校验位
string[] parity = {
"None", "Odd", "Even", "Mark", "Speace" };
cmbParity.Items.AddRange(parity);
//默认值设置
cmbPortName.SelectedIndex = cmbPortName.Items.Count > 0 ? 0 : -1;
cmbBaudrate.SelectedIndex = cmbBaudrate.Items.IndexOf("9600");
cmbDataBits.SelectedIndex = cmbDataBits.Items.IndexOf("8");
cmbStopBits.SelectedIndex = cmbStopBits.Items.IndexOf("1");
cmbParity.SelectedIndex = cmbParity.Items.IndexOf("None");
//下拉框只可选择不可编辑
cmbPortName.DropDownStyle = ComboBoxStyle.DropDownList;
cmbBaudrate.DropDownStyle = ComboBoxStyle.DropDownList;
cmbDataBits.DropDownStyle = ComboBoxStyle.DropDownList;
cmbStopBits.DropDownStyle = ComboBoxStyle.DropDownList;
cmbParity.DropDownStyle = ComboBoxStyle.DropDownList;
//初始化SerialPort对象
comm.NewLine = "\r\n";
//根据实际情况吧。
comm.RtsEnable = true;
//添加事件注册
comm.DataReceived += cmb_DataReceived;
}
///
/// Com口接收数据
///
///
///
void cmb_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
int n = comm.BytesToRead;//先记录下来,避免某种原因,人为的原因,操作几次之间时间长,缓存不一致
byte[] buf = new byte[n];//声明一个临时数组存储当前来的串口数据
comm.Read(buf, 0, n);//读取缓冲数据
string lineStr = System.Text.Encoding.Default.GetString(buf);
lineStr = Util.DealNotSeeToSeeChar(lineStr);
if (pushToSwitch != null)
{
pushToSwitch(buf, type);
}
}
///
/// 启动
///
///
///
private void btnStart_Click(object sender, EventArgs e)
{
Start();
}
///
/// 停止
///
///
///
private void btnStop_Click(object sender, EventArgs e)
{
Stop();
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
using System.Threading;
namespace MessageSwitch
{
///
/// [功能描述:TCP服务端实现]
/// [创建者:zlz]
/// [创建时间:2021年11月13日]
///<说明>
/// [说明:TCP服务端实现]
///
///<修改记录>
/// [修改时间:本次修改时间]
/// [修改内容:本次修改内容]
///
///<修改记录>
/// [修改时间:本次修改时间]
/// [修改内容:本次修改内容]
///
///
public partial class UCTcpServer : UserControl, IMessageSwitch
{
///
/// 网络服务对象
///
private Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
///
/// 是否打开
///
private bool IsOpen = false;
///
/// 推送器
///
private PushMessageToSwitch pushToSwitch;
///
/// 类型
///
SwitchType type;
///
/// 写日志委托
///
private WriteLog log;
///
/// 网络客户端
///
public Socket mianClient = null;
///
/// 构造函数
///
public UCTcpServer()
{
InitializeComponent();
}
///
/// 得到类型名字
///
///
public string GetTypeName()
{
return "TCP服务端";
}
///
/// 得到配置
///
///
public string GetConfig()
{
string confStr = txtIp.Text + "#" + txtPort.Text;
return confStr;
}
///
/// 设置配置
///
///
///
public bool SetConfig(string confStr)
{
string[] arr = confStr.Split('#');
if (arr.Length != 2)
{
MessageBox.Show("TCP配置格式不对!应该是#分隔的2位", "提示");
return false;
}
txtIp.Text = arr[0];
txtPort.Text = arr[1];
return true;
}
///
/// 设置推送委托
///
/// 推送器
/// 类型
/// 日志委托
///
public bool SetPushDelegate(PushMessageToSwitch push, SwitchType ptype, WriteLog plog)
{
pushToSwitch = push;
type = ptype;
log = plog;
return true;
}
///
/// 启动
///
///
public bool Start()
{
if (txtPort.Text == "")
{
if (log != null)
{
log("启动:没有设置端口号");
}
return false;
}
if (txtIp.Text == "")
{
if (log != null)
{
log("启动:没有设置端IP");
}
return false;
}
//先释放
if (socket != null)
{
socket.Close();
socket.Dispose();
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IsOpen = false;
}
//绑定IP端口
IPAddress hostIP = IPAddress.Any;
IPAddress.TryParse(txtIp.Text, out hostIP);
if (Util.PortInUse(Convert.ToInt32(txtPort.Text)))
{
if (log != null)
{
log("启动TCP服务:当前电脑端口:" + txtPort.Text + "已经被占用");
}
//现实异常信息给客户。
MessageBox.Show("当前电脑端口:" + txtPort.Text + "已经被占用", "提示", MessageBoxButtons.OK);
return false;
}
IPEndPoint ep = new IPEndPoint(hostIP, Convert.ToInt32(txtPort.Text));
socket.Bind(ep);
try
{
//开始侦听
socket.Listen(20);
if (log != null)
{
log("启动TCP服务:启动TCP服务成功");
}
stateIp.ForeColor = Color.Blue;
Thread tcpThread = new Thread(new ThreadStart(TcpListenClientConnect));
IsOpen = true;
tcpThread.Start();
return true;
}
catch (Exception ex)
{
IsOpen = false;
//现实异常信息给客户。
MessageBox.Show(ex.Message, "提示", MessageBoxButtons.OK);
return false;
}
}
///
/// 停止
///
///
public bool Stop()
{
if (socket != null)
{
socket.Close();
stateIp.ForeColor = Color.Red;
socket.Dispose();
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IsOpen = false;
if (log != null)
{
log("停止TCP服务:TCP已释放");
}
}
return true;
}
///
/// 给tcp发送消息
///
///
///
public bool SendMessage(byte[] msgByteArr)
{
//转发给TCP
if (mianClient != null)
{
mianClient.Send(msgByteArr);
return true;
}
else
{
if (log != null)
{
log("TCP无连接客户端,无法发送,确认防火墙关闭!");
}
return false;
}
}
///
/// 得到反射串
///
///
public string GetReflectStr()
{
return "MessageSwitch.UCTcpServer,MessageSwitch.dll";
}
///
/// 加载方法
///
///
///
private void UCTcpServer_Load(object sender, EventArgs e)
{
txtIp.Text = Util.GetIpv4Str();
}
///
/// 监听客户端连接
///
private void TcpListenClientConnect()
{
//死循环侦听客户端连接
while (true)
{
try
{
if (IsOpen == false)
{
break;
}
//有客户端连接过来
Socket oneClient = socket.Accept();
string clentIP = ((IPEndPoint)oneClient.RemoteEndPoint).Address.ToString();
string clientPort = ((IPEndPoint)oneClient.RemoteEndPoint).Port.ToString();
if (log != null)
{
log("客户端:" + clentIP + ":" + clientPort + "连接了本服务");
}
//服务只接收一个客户端
if (mianClient == null)
{
if (log != null)
{
log("客户端:" + clentIP + ":" + clientPort + "作为主客户端");
}
mianClient = oneClient;
Thread newThread = new Thread(ListenClientData);
newThread.Start();
}
else
{
if (log != null)
{
log("已有客户端连接本服务,将断开当前客户端请求");
}
//有客户端连着就不让其他客户端连接了
byte[] byteArray = System.Text.Encoding.Default.GetBytes("已有连接连上该端口了!");
oneClient.Send(byteArray);
oneClient.Close();
}
}
catch (Exception ex)
{
if (log != null)
{
log("服务端侦听异常:" + ex.Message);
}
}
}
}
///
/// 侦听客户端消息
///
public void ListenClientData()
{
byte[] bytes = new byte[83886080];
//数量
int datai = -1;
try
{
//死循环侦听客户端发来的数据
while (true)
{
if (IsOpen == false)
{
break;
}
datai = mianClient.Receive(bytes);
if (datai > 0)
{
if (pushToSwitch != null)
{
byte[] buf = new byte[datai];
Array.Copy(bytes, buf, datai);
pushToSwitch(buf, type);
}
}
}
}
catch (System.Exception ex)
{
if (log != null)
{
log("侦听客户端消息异常:" + ex.Message);
}
}
finally
{
if (mianClient != null)
{
mianClient.Close();
mianClient.Dispose();
mianClient = null;
}
}
}
///
/// 启动
///
///
///
private void btnStart_Click(object sender, EventArgs e)
{
Start();
}
///
/// 停止
///
///
///
private void btnStop_Click(object sender, EventArgs e)
{
Stop();
}
}
}
工具类,共用方法
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml.Serialization;
using System.Net.NetworkInformation;
using System.Net;
namespace MessageSwitch
{
///
/// [功能描述:工具类]
/// [创建者:zlz]
/// [创建时间:2021年11月13日]
///<说明>
/// [说明:工具类]
///
///<修改记录>
/// [修改时间:本次修改时间]
/// [修改内容:本次修改内容]
///
///<修改记录>
/// [修改时间:本次修改时间]
/// [修改内容:本次修改内容]
///
///
public class Util
{
///
/// 反序列化数据
///
///
///
///
public static T ReadLocalData<T>(string path)
{
if (File.Exists(path))
{
try
{
string str = ReadTxt(path);
byte[] arr = Convert.FromBase64String(str);
str = System.Text.Encoding.Default.GetString(arr);
return XmlDeserialize<T>(str, Encoding.UTF8);
}
catch (Exception e)
{
throw e;
}
}
else
{
return default(T);
}
}
///
/// 序列化数据
///
///
///
///
public static bool WriteLocalData(object data, string path)
{
if (File.Exists(path))
{
File.Delete(path);
try
{
string str = Serializer(data.GetType(), data);
byte[] arr = System.Text.Encoding.Default.GetBytes(str);
str = Convert.ToBase64String(arr);
WriteTxt(path, str);
return true;
}
catch (Exception e)
{
throw e;
}
}
else
{
try
{
string str = Serializer(data.GetType(), data);
byte[] arr = System.Text.Encoding.Default.GetBytes(str);
str = Convert.ToBase64String(arr);
WriteTxt(path, str);
return true;
}
catch (Exception e)
{
throw e;
}
}
}
///
/// 删除本地数据
///
/// Id
/// 路径,不给的话有方法默认决定
/// 结果
public static bool DeleteLocalData(string id, string pat)
{
string path = Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), id + ".aup");
if (pat != null && pat != string.Empty)
{
path = Path.Combine(pat, id + ".aup");
}
if (File.Exists(path))
{
File.Delete(path);
}
return true;
}
///
/// 序列化
///
/// 类型
/// 对象
///
public static string Serializer(Type type, object obj)
{
MemoryStream Stream = new MemoryStream();
XmlSerializer xml = new XmlSerializer(type);
try
{
//序列化对象
xml.Serialize(Stream, obj);
}
catch (InvalidOperationException)
{
throw;
}
Stream.Position = 0;
StreamReader sr = new StreamReader(Stream);
string str = sr.ReadToEnd();
sr.Dispose();
Stream.Dispose();
return str;
}
///
/// 从XML字符串中反序列化对象
///
/// 结果对象类型
/// 包含对象的XML字符串
/// 编码方式
/// 反序列化得到的对象
public static T XmlDeserialize<T>(string s, Encoding encoding)
{
try
{
if (string.IsNullOrEmpty(s))
{
throw new ArgumentNullException("s");
}
if (encoding == null)
{
throw new ArgumentNullException("encoding");
}
XmlSerializer mySerializer = new XmlSerializer(typeof(T));
using (MemoryStream ms = new MemoryStream(encoding.GetBytes(s)))
{
using (StreamReader sr = new StreamReader(ms, encoding))
{
return (T)mySerializer.Deserialize(sr);
}
}
}
catch (Exception ex)
{
return default(T);
}
}
///
/// 读取文件数据
///
/// 文件全路径
///
public static string ReadTxt(string path)
{
//文件流
FileStream fs = null;
try
{
//创建文件流
fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
//创建字符串读取器
StreamReader sr = new StreamReader(fs);
//读到尾
string str = sr.ReadToEnd();
return str;
}
finally
{
if (fs != null)
{
fs.Close();
}
}
}
///
/// 写入数据到指定文件
///
/// 文件全路径
/// 数据
/// 是否提换,默认为替换,否则为添加
///
public static bool WriteTxt(string path, string str)
{
FileStream fs = null;
StreamWriter sw1 = null;
try
{
if (File.Exists(path))
{
File.Delete(path);
}
//创建文件流
fs = new FileStream(path, FileMode.CreateNew);
//创建字符串写入器
sw1 = new StreamWriter(fs);
//写入字符串
sw1.Write(str);
return true;
}
catch (Exception ex)
{
throw ex;
}
finally
{
if (sw1 != null)
{
sw1.Close();
}
if (fs != null)
{
fs.Close();
}
}
}
///
/// 处理不可见字符
///
/// 数据
/// 返回
public static string DealNotSeeToSeeChar(string data)
{
for (int i = 0; i <= 31; i++)
{
if (i == 6)
{
data = data.Replace((char)i + "", "[ACK]");
}
else if (i == 5)
{
data = data.Replace((char)i + "", "[ENQ]");
}
else if (i == 4)
{
data = data.Replace((char)i + "", "[EOT]");
}
else if (i == 3)
{
data = data.Replace((char)i + "", "[ETX]");
}
else if (i == 2)
{
data = data.Replace((char)i + "", "[STX]");
}
else
{
data = data.Replace((char)i + "", "[" + i + "]");
}
}
data.Replace((char)127 + "", "[127]");
return data;
}
///
/// 判断端口是否被占用
///
/// 端口
///
public static bool PortInUse(int port)
{
bool inUse = false;
IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
IPEndPoint[] ipEndPoints = ipProperties.GetActiveTcpListeners();
foreach (IPEndPoint endPoint in ipEndPoints)
{
if (endPoint.Port == port)
{
inUse = true;
break;
}
}
return inUse;
}
///
/// 获得当前机器的ip4串
///
///
public static string GetIpv4Str()
{
System.Net.IPAddress[] arrIPAddresses = System.Net.Dns.GetHostAddresses(System.Net.Dns.GetHostName());
foreach (System.Net.IPAddress ip in arrIPAddresses)
{
if (ip.AddressFamily.Equals(System.Net.Sockets.AddressFamily.InterNetwork))
{
return ip.ToString();
}
}
return string.Empty;
}
}
}
这样就可以任意组合转换器两端的协议了。可以串口转串口,串口转tcp,tcp转tcp,tcp转tdp,串口转udp====。而且每端可以配置多种协议。所以把这个称为超级转换器。分为转换中心和转换实现。
善于抽取共性,就能大大降低复杂度,实现灵活又强大的功能,面向接口编程的好处。