十四、自定义串口转网口(TCP和UDP连接方式)

一、思路图

二、发数据:客户端 <使用安装的的软件测试> ---服务端 <代码编写> ---串口。(返回数据:串口---服务端---客户端)

namespace SerialToNetWork
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            //string[] strings = SerialPort.GetPortNames();
        }


        private void Form1_Load(object sender, EventArgs e)
        {
            //给数据位下拉框赋值
            cbData.Items.AddRange(new object[] {8,7,6,5 });
            //获取奇偶校验枚举中的数据名称
            string[] paritys = Enum.GetNames(typeof(Parity));
            cbParity.Items.AddRange(paritys);
            //获取停止位枚举中的数据名称
            string[] stops = Enum.GetNames(typeof(StopBits));
            cbStop.Items.AddRange(stops);

            //初始化ini文件操作
            //串口数据
            string portName = iniUtil.Read("Serial", "PortName");//名称
            int baudRate = iniUtil.ReadInt("Serial", "BaudRate", 4800);//波特率
            int dataBits = iniUtil.ReadInt("Serial", "DataBits", 8);//数据位
            int parity = iniUtil.ReadInt("Serial", "Parity", 0);//奇偶校验
            int stopBits = iniUtil.ReadInt("Serial", "StopBits", 1);//停止位
            //网络数据 
            int port = iniUtil.ReadInt("TcpService", "Port", 8500);//端口
            //心跳数据

            bool heartbeat = iniUtil.ReadBool("Heartbeat","rbHeart",false);
            int heartSpace = iniUtil.ReadInt("Heartbeat","heartSpacer",60*1000);

            //需要改ReadStr()
            string heartPart = iniUtil.Read("Heartbeat", "heartPart");
            bool heartIsHex = iniUtil.ReadBool("Heartbeat", "IsHex", true);

            //给文本框赋值
            tbSerial.Text = portName;
            tbRate.Text = baudRate.ToString();
            cbData.Text = dataBits.ToString();
            cbParity.SelectedIndex = parity;
            cbStop.SelectedIndex = stopBits;
            tbPort.Text = port.ToString();
            ckIsHex.Checked = heartIsHex;
            rbHeartClose.Checked = !heartbeat;
            rbHeartOpen.Checked = heartbeat;
            tbHeartSpacer.Text = heartSpace.ToString();
            tbHeartPart.Text = heartPart;

            Task.Run(async () => 
            {
                while (true) 
                {
                    //循环启动串口
                    StartSerial(portName, baudRate, dataBits, (Parity)parity, (StopBits)stopBits);
                    await Task.Delay(1000);
                }
            });
            
            //启动服务端
            StartTcpService(port);

            //启动心跳
            if (heartbeat)  //心跳开关
            {
                byte[] buffer;
                if (heartIsHex) //心跳为16进制
                {
                    string[] hexs = heartPart.Split(new string[] { " "},StringSplitOptions.RemoveEmptyEntries);
                    buffer = new byte[hexs.Length];
                    for (int i = 0; i < hexs.Length; i++)
                    {
                        buffer[i] = Convert.ToByte(hexs[i], 16);
                    }
                }
                else //心跳为字符串
                {
                    buffer = Encoding.UTF8.GetBytes(heartPart);
                }
                timer1.Enabled = true;
                timer1.Interval = heartSpace;
                timer1.Tick += (s1,e1) => 
                {
                    //发送心跳
                    if (clients.Count == 0) 
                    {
                        return;
                    }
                    for (int i=0;i<clients.Count;i++) 
                    {
                        clients[i].Send(buffer);
                    }
                };

            }
           
        }

        //启动串口
        private void StartSerial(string portName, int baudRate, int dataBits, Parity parity, StopBits stopBits)
        {
            if (serialPort1.IsOpen)
            {
                return;
            }
            try
            {
                serialPort1.PortName = portName;
                serialPort1.BaudRate = baudRate;
                serialPort1.DataBits = dataBits;
                serialPort1.Parity = parity;
                serialPort1.StopBits = stopBits;
                serialPort1.Open();
                Console.WriteLine("串口启动成功");
                serialLight.ForeColor = Color.Lime;
            }
            catch (Exception ex)
            {
                Console.WriteLine("串口打开失败:"+ex.Message);
                serialLight.ForeColor = Color.Black;
            }
        }



        //启动TCP服务端
        private List<Socket> clients = new List<Socket>();
        Socket service;
        private void StartTcpService(int port) 
        {
            service = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            try 
            {
                service.Bind(new IPEndPoint(IPAddress.Any, port));
                service.Listen(8);
                Console.WriteLine("服务端启动成功");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"启动服务端异常:+{ex.Message}");
                return;
            }
            
            Task.Run(() =>
            {
                while (true) 
                {
                    try
                    {
                        Socket client = service.Accept();//等待客户端连接
                        this.BeginInvoke(new Action(() =>
                        {
                            TcpServiceLight.ForeColor = Color.Lime;
                        }));
                        clients.Add(client);//将客户端连接存入集合
                        ReceviceClientData(client);//接收客户端消息
                    } catch (Exception ex)
                    {
                        Console.WriteLine("等待客户端连接异常:{0}",ex.Message);
                    }      
                }
            });
        }
        //循环接收客户端消息
        private void ReceviceClientData(Socket client)
        {
            Task.Run(() => 
            {
                try 
                {
                    while (true)
                    {
                        byte[] buffer = new byte[1024];
                        int length = client.Receive(buffer);
                        if (length == 0) 
                        {
                            throw new Exception("客户端发送的消息长度为0,认为客户端下线了");
                        }
                       
                        this.BeginInvoke(new Action(() =>
                        {
                            //接收数据时亮灯
                            LighterUp(ligtherGet);
                            tbGet.Text = length.ToString() + "字节";
                        }));
                        //第3步,把消息发送给串口设备
                        if (serialPort1.IsOpen)
                        {
                            serialPort1.Write(buffer, 0, length);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"接收{client.RemoteEndPoint.ToString()}:客户端消息异常"+ex.Message);
                    this.BeginInvoke(new Action(() =>
                    {
                        tbGet.Text = "0";
                    }));
                    CloseTcpClient(client);//关闭客户端
                }
            });
        }

        //Tcp服务端接收串口发送过来的消息
        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            //读取串口数据
            byte[] buffer = new byte[serialPort1.BytesToRead];
            int length = serialPort1.Read(buffer, 0, buffer.Length);
            //给每一个客户端发送数据
            int count = clients.Count;
            for (int i = 0;i<count;i++) 
            {
                Socket client = clients[i];
                //给客户端发送数据
                int length1 = client.Send(buffer,0,length,SocketFlags.None);
                this.BeginInvoke(new Action(() =>
                {
                    LighterUp(lighterTo);
                    tbTo.Text = length1.ToString() + "字节";
                    
                }));
            }
        }

        //关闭TCP客户端
        private void CloseTcpClient(Socket client) 
        {
            if (clients.Contains(client)) 
            {
                clients.Remove(client);
            }
            client?.Close();
            this.BeginInvoke(new Action(() =>
            {
                tbTo.Text = "0";
                TcpServiceLight.ForeColor = Color.Black;
            }));
        }


        //接收和发送消息时亮一下灯
        private void LighterUp(Control lighter) 
        {
            this.BeginInvoke(new Action(async () =>
            {
                lighter.BackColor = Color.Lime;
                await Task.Delay(60);
                lighter.BackColor = Color.White;
            }));
        }

       
        //清空接收或者发送字节框
        private void Clear1_DoubleClick(object sender, EventArgs e)
        {
            Label lab = sender as Label;
            if (lab.Text == "清空接收")
            {
                tbGet.Text = "0";
            }
            else if (lab.Text == "清空发送")
            {
                tbTo.Text = "0";
            }
        }

        //保存数据到ini文件
        private void btnSave_Click(object sender, EventArgs e)
        {
            
            
            iniUtil.Write("Serial", "PortName", tbSerial.Text);//串口名称
            iniUtil.Write("Serial", "BaudRate", tbRate.Text);//波特率
            iniUtil.Write("Serial", "DataBits", cbData.Text);//数据位
            iniUtil.Write("Serial", "Parity", cbParity.SelectedIndex.ToString());//奇偶校验
            iniUtil.Write("Serial", "StopBits", cbStop.SelectedIndex.ToString());//停止位
            iniUtil.Write("TcpService", "Port",tbPort.Text);//端口
            iniUtil.Write("Heartbeat", "rbHeart", Convert.ToString(rbHeartOpen.Checked));//心跳是否关闭
            iniUtil.Write("Heartbeat", "heartSpacer",tbHeartSpacer.Text);//心跳间隔
            iniUtil.Write("Heartbeat", "heartPart", tbHeartPart.Text);//心跳内容
            iniUtil.Write("Heartbeat", "IsHex", Convert.ToString(ckIsHex.Checked));//心跳内容

            MessageBox.Show("保存成功");
        }


        //重启
        private void startAgain_Click(object sender, EventArgs e)
        {
            service?.Close();
            if (serialPort1.IsOpen) 
            {
                serialPort1.Close();
            }
            //重启一个程序,方法一
            //this.Close();
            //Application.ExecutablePath==>获取当前程序路径(包含程序名称exe)
            //Process.Start(Application.ExecutablePath);
            //方法二
            Application.Restart();
        }
    }
}                               

 三、发生数据:TCP服务端 <安装的测试软件> --- TCP客户端 <代码编写> --- 串口。(返回数据:串口 --- 客户端 --- 服务端)。

namespace SerialToNetWorkTcpClient
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        Socket client;

        private void btnOpenOrClose_Click(object sender, EventArgs e)
        {
            if (btnOpenOrClose.Text == "打开客户端")
            {

                Task.Run(new Action(() =>
                {
                    StartClient();
                }));
                    
                btnOpenOrClose.Text = "关闭客户端";
                btnOpenOrClose.ForeColor = Color.Red;
               
            }
            else if(btnOpenOrClose.Text == "关闭客户端")
            {
                client?.Close();
                btnOpenOrClose.Text = "打开客户端";
                btnOpenOrClose.ForeColor = Color.Black;
            }
        }

        //开启客户端
        private void StartClient() 
        {
            client = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
            try 
            {
                client.Connect(new IPEndPoint(IPAddress.Parse("192.168.152.1"), 5005));
                Console.WriteLine("客户端启动成功");
                 //循环接收服务端发送过来的数据
                while (true)
                {
                    byte[] buffer = new byte[1024];
                    int length = client.Receive(buffer);
                    if (length == 0)
                    {
                        MessageBox.Show("服务端关闭");
                        return;
                    }
                    //把接收到的服务端数据发给串口
                    if (serialPort1.IsOpen) 
                    {
                        serialPort1.Write(buffer, 0, length);
                    }
                }
            } 
            catch(Exception ex) 
            {
                Console.WriteLine("未连接上服务端:"+ex.Message);
            }  
           
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Task.Run(new Action(async () => 
            {
                while (true)
                {
                    StartSearial();
                    await Task.Delay(1000);
                }
            }));
            

    }

        //启动串口
        private void StartSearial() 
        {
            if (!serialPort1.IsOpen) 
            {
                //获取ini文件数据
                string portName = iniUtil.Read("Serial", "PortName");//名称
                int baudRate = iniUtil.ReadInt("Serial", "BaudRate", 4800);//波特率
                int dataBits = iniUtil.ReadInt("Serial", "DataBits", 8);//数据位
                int parity = iniUtil.ReadInt("Serial", "Parity", 0);//奇偶校验
                int stopBits = iniUtil.ReadInt("Serial", "StopBits", 1);//停止位
                                                                        //设置串口数据
                serialPort1.PortName = portName;
                serialPort1.BaudRate = baudRate;
                serialPort1.DataBits = dataBits;
                serialPort1.Parity = (Parity)parity;
                serialPort1.StopBits = (StopBits)stopBits;
                try
                {
                    //启动串口
                    serialPort1.Open();
                    Console.WriteLine("串口启动成功");
                }
                catch (Exception ex)
                {
                    Console.WriteLine("串口启动失败:" + ex.Message);
                    return;
                }
            }
        }

        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            byte[] buffer = new byte[serialPort1.BytesToRead];
            int length = serialPort1.Read(buffer,0,buffer.Length);
            if (client != null && client.Connected) 
            {
                StringBuilder sb = new StringBuilder();
                for (int i =0;i<buffer.Length;i++) 
                {
                    sb.Append(buffer[i].ToString("X2")+" ");
                }
                this.Invoke(new Action(() =>
                {
                    rbData.Text += sb;
                }));
                client.Send(buffer,0,buffer.Length,SocketFlags.None);
            }
        }

        //清空接收
        private void btnClose_Click(object sender, EventArgs e)
        {
            rbData.Text = "";
        }
    }
}

四、 发送数据:UDP连接 <安装的测试软件,去连接已经在代码中编写设置好的UDP连接> --- UDP<代码创建一个UDP连接(绑定好IP和端口)> --- 串口。(返回数据:串口 --- 客户端 --- 服务端)。

namespace SerialToNetWorkUdpClient
{

    public partial class Form1 : Form
    {
        //udp服务端接收客户端的指令,发送给串口,在从串口得到的数据转发给客户端
        public Form1()
        {
            InitializeComponent();
        }

        

        private void btnOpenOrClose_Click(object sender, EventArgs e)
        {
            if (btnOpenOrClose.Text == "打开连接")
            {
                Task.Run(new Action(() =>
                {
                    OpClient();
                }));

                btnOpenOrClose.Text = "关闭连接";
                btnOpenOrClose.ForeColor = Color.Red;

            } 
            else if (btnOpenOrClose.Text == "关闭连接") 
            {
                client?.Close();
                btnOpenOrClose.Text = "打开连接";
                btnOpenOrClose.ForeColor = Color.Black;
            }
        }

        Socket client = null;
        private EndPoint endP;
        /// <summary>
        /// 开启Udp客户端
        /// </summary>
        private void OpClient()
        {
            if (client == null)
            { 
                client = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                try
                {
                   client.Bind(new IPEndPoint(IPAddress.Parse("192.168.22.1"), 9000));
                    Console.WriteLine("Udp客户端连接成功");
                    endP = new IPEndPoint(0, 0);
                    //循环接收服务端发送过来的数据
                    while (true)
                    {
                        
                        byte[] buffer = new byte[1024];
                        int length = client.ReceiveFrom(buffer, ref endP);
                        if (length == 0)
                        {
                            MessageBox.Show("服务端关闭");
                            return;
                        }
                        //把接收到的服务端数据发给串口
                        if (serialPort1.IsOpen)
                        {
                            serialPort1.Write(buffer,0, length);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("没有连接:" + ex.Message);
                }


            }
        }

        //启动串口
        private void StartSearial()
        {
            if (!serialPort1.IsOpen)
            {
                //获取ini文件数据
                string portName = iniUtil.Read("Serial", "PortName");//名称
                int baudRate = iniUtil.ReadInt("Serial", "BaudRate", 4800);//波特率
                int dataBits = iniUtil.ReadInt("Serial", "DataBits", 8);//数据位
                int parity = iniUtil.ReadInt("Serial", "Parity", 0);//奇偶校验
                int stopBits = iniUtil.ReadInt("Serial", "StopBits", 1);//停止位
                //设置串口数据
                serialPort1.PortName = portName;
                serialPort1.BaudRate = baudRate;
                serialPort1.DataBits = dataBits;
                serialPort1.Parity = (Parity)parity;
                serialPort1.StopBits = (StopBits)stopBits;
                try
                {
                    //启动串口
                    serialPort1.Open();
                    Console.WriteLine("串口启动成功");
                }
                catch (Exception ex)
                {
                    Console.WriteLine("串口启动失败:" + ex.Message);
                    return;
                }
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            //循环开启串口
            Task.Run(new Action(async () =>
            {
                while (true)
                {
                    StartSearial();
                    await Task.Delay(1000);
                }
            }));
        }

        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            byte[] buffer = new byte[serialPort1.BytesToRead];
            int length = serialPort1.Read(buffer, 0, buffer.Length);
            if (client != null && !client.Connected)
            {
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < buffer.Length; i++)
                {
                    sb.Append(buffer[i].ToString("X2") + " ");
                }
                this.Invoke(new Action(() =>
                {
                    rbData.Text += sb;
                }));
                client.SendTo(buffer, 0, buffer.Length, SocketFlags.None,endP);
            }
        }

        private void btnClear_Click(object sender, EventArgs e)
        {
            rbData.Text = "";
        }
    }
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
设计方案: 本监控设备需要能够连接多个传感器和设备,因此需要多个串口和多个网口。每个串口连接一个传感器或设备,每个网口连接服务器。在该设备中,采用C语言编写,可以使用Linux操作系统进行开发。为了保证设备能够长时间稳定工作,可以采用嵌入式Linux系统。可以使用设计模式来提高代码的可维护性和可扩展性。以下是设计方案的详细说明。 硬件设计: 该设备需要多个串口和多个网口。可以选择嵌入式开发板,例如树莓派、Rock Pi、FriendlyARM等,这些开发板都有多个串口和多个网口串口网口可以连接到开发板的GPIO引脚上。可以使用GPIO库来控制这些引脚。 软件设计: 在软件设计方面,可以使用以下设计模式: 1. 工厂模式 使用工厂模式来创建传感器和设备的实例。这样可以在程序运行时动态地创建传感器和设备对象,提高代码的可扩展性。在创建传感器和设备对象时,可以使用参数配置来设置对象的属性。 2. 单例模式 使用单例模式来保证只有一个实例能够连接服务器。这样可以防止多个实例同时连接服务器,导致连接错误或冲突。 3. 观察者模式 使用观察者模式来实现数据采集。将传感器和设备对象作为观察者,将它们注册到数据采集器对象上。当数据采集器对象接收到数据时,会通知所有的观察者对象,观察者对象可以对数据进行处理和存储。 4. 策略模式 使用策略模式来实现数据处理。可以定义多个数据处理策略,例如平均值、最大值、最小值等。将数据处理策略对象作为参数传递给数据处理器对象,数据处理器对象根据传入的数据处理策略进行数据处理。 5. 装饰者模式 使用装饰者模式来扩展串口网口的功能。可以为串口网口对象添加缓冲区、数据压缩、数据加密等功能,提高数据传输效率和安全性。 代码实现: 以下是示例代码实现: ```c #include <stdio.h> #include <stdlib.h> #include <pthread.h> // 工厂模式 typedef struct sensor { int id; int value; } Sensor; typedef struct device { int id; int status; } Device; Sensor* create_sensor(int id) { Sensor* sensor = (Sensor*)malloc(sizeof(Sensor)); sensor->id = id; sensor->value = 0; return sensor; } Device* create_device(int id) { Device* device
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值