SerialportToTCP② 全

发布于:2024-07-04 ⋅ 阅读:(23) ⋅ 点赞:(0)

效果补全(代码):

namespace SerialportToTCP
{
    public partial class Form1 : Form
    {
        IniHelper Ini;
        string[] botelvs = new string[] { "1200", "4800", "9600", "13200" };
        public Form1()
        {
            InitializeComponent();

            //1 读取配置文件
            string dirPath = Path.Combine(Application.StartupPath, "File");// debug/file
            string filePath = Path.Combine(dirPath, "Setting.ini");// debug / file/setting.ini
            Ini = new IniHelper(filePath); //创建读取对象

            // 添加串口
            comboBox1.Items.AddRange(SerialPort.GetPortNames());// 获取所有串口 拼接在下拉框的items中
            comboBox2.Items.AddRange(botelvs);// 添加波特率数组
            comboBox2.Items.Add("自定义");//添加一个
            comboBox3.Items.AddRange(new string[] { "5", "6", "7", "8" });
            comboBox4.Items.AddRange(new string[] { "无", "奇校检", "偶校检" });
            comboBox5.Items.AddRange(new string[] { "无", "1", "2", "1.5" });


            //2开始处理串口接受数据事件
            //处理串口的数据
            this.serialPort1.DataReceived += SerialPort1_DataReceived;

            //3 处理界面显示默认值 也就是从ini文件读取数据
            readSetting();

            //4 开始串口通信
            startChuanKou();

            //5 开始网口通信
            startTCP();


        }
        //开始搭建TCP服务器
        TcpListener listen;
        List<TcpClient> lists = new List<TcpClient>();//存放所有的客户端
        void startTCP()
        {
            if(!int.TryParse(textBox3.Text,out int port) || port < 1 || port >65563)
            {
                MessageBox.Show("请输入正确的端口号");
            }
            //开启服务器 接受客户端
            try
            {
                 listen = new TcpListener(System.Net.IPAddress.Any, port);
                listen.Start(100); //开始监听
                panel2.BackColor = Color.Green;

                //把多个客户端接受到数组里面 异步接受
                new Task(() => {
                    try
                    {
                        while (true)
                        {
                            //接收客户端
                            TcpClient c1 = listen.AcceptTcpClient();

                            // 把客户端添加到数组里面 群发需要
                            lists.Add(c1);

                            //接收客户端发来的消息
                            tcpReceive(c1);
                        }
                    }
                    catch
                    {
                        MessageBox.Show("TCP服务器关闭");
                    }
                }).Start();
            }
            catch
            {
                MessageBox.Show("TCP启动失败");
                //把tcp关闭等操作
                foreach (var item in lists)
                {
                    item.Close(); //关闭所有的客户端
                }
                listen.Stop();
                panel2.BackColor = Color.Gray;
            }

        }
        //tcp 接收数据
        void tcpReceive(TcpClient c1)
        {
            
            new Task(() =>
            {
                NetworkStream stream = c1.GetStream();
              
                try
                {
                  
                    while (c1.Connected) //客户端连接的时候
                    {
                        byte[] bs = new byte[1024];
                        int length =  stream.Read(bs, 0, bs.Length);
                        if (length == 0) throw new Exception(); // 客户端断了
                        //接收到数据亮灯
                        tcpLiangDeng();

                        //把数据转给串口
                        if (!serialPort1.IsOpen)
                        {
                            MessageBox.Show("串口关闭");
                            break;
                        }
                        //把数据转给串口 serialPort1发送数据, com6能接受到消息,
                        serialPort1.Write(bs, 0, length);
                    }
                }
                catch
                {

                    c1.Close();
                    lists.Remove(c1);
                }

            }).Start();
        }
        //tcp 接收到数据亮灯的方法
        async void tcpLiangDeng()
        {
            this.Invoke((Action)(() =>
            {
                textBox2.Text = (int.Parse(textBox2.Text) + 1).ToString();
                //亮灯
                panel4.BackColor = Color.Green;
            }));

            //过一段时间
            await Task.Delay(70);

            this.Invoke((Action)(() =>
            {
                //关灯
                panel4.BackColor = Color.Gray;
            }));
        }
        void startChuanKou()
        {
            // 配置串口对象
            try
            {
                this.serialPort1.PortName = comboBox1.Text;//配置串口名称
                this.serialPort1.BaudRate = int.Parse(comboBox2.Text); //波特率
                this.serialPort1.DataBits = int.Parse( comboBox3.Text);
                this.serialPort1.StopBits = (StopBits)comboBox5.SelectedIndex;// 正常赋值 StopBits.None 枚举值。正好对应数据0
                this.serialPort1.Parity = (Parity)comboBox4.SelectedIndex; // 

                this.serialPort1.Open();
                //亮灯
                this.panel1.BackColor = Color.Green;

            }
            catch
            {
                MessageBox.Show("打开串口失败");
                //停止串口
                if(serialPort1.IsOpen) serialPort1.Close();
                //灭灯
                this.panel1.BackColor = Color.Gray;

            }
            
        }
        void readSetting()
        {
            //先配置串口
            comboBox1.SelectedItem = Ini.Read("Serialport", "name", "");
            string botelv = Ini.Read("Serialport", "botelv", "9601");
            int botelvIndex = Array.IndexOf(botelvs, botelv);// 获取botelv在数组里面的索引值
            if (botelvIndex != -1) // 证明波特率在数组里面
            {
                comboBox2.SelectedIndex= botelvIndex;
                comboBox2.DropDownStyle = ComboBoxStyle.DropDownList;
            }
            else
            {
                //波特率在数组里面 自定义波特率情况
                comboBox2.DropDownStyle = ComboBoxStyle.DropDown; //可编辑的下拉框
                //DropDownList 不可编辑的下拉框
                comboBox2.Text = botelv;
            }
            //处理数据位
            comboBox3.SelectedItem = Ini.Read("Serialport", "databit", "8");
            //处理奇偶校检
            comboBox4.SelectedIndex = Ini.Read("Serialport", "parity", 0);
            comboBox5.SelectedIndex = Ini.Read("Serialport", "stopbit", 0);

            comboBox1.DropDownStyle = ComboBoxStyle.DropDownList;
            comboBox3.DropDownStyle = ComboBoxStyle.DropDownList;
            comboBox4.DropDownStyle = ComboBoxStyle.DropDownList;
            comboBox5.DropDownStyle = ComboBoxStyle.DropDownList;


            //网口数据的读取
            textBox3.Text = Ini.Read("NetWork", "port", "8080");
           if( Ini.Read("NetWork", "heartOn", false))
           {
                radioButton1.Checked = true;
           }
            else
            {
                radioButton2.Checked = true;
            }
            textBox4.Text= Ini.Read("NetWork", "heartTime", "60000");// 心跳间隔  
            textBox5.Text = Ini.Read("NetWork", "heartData", ""); //心跳包数据
            checkBox1.Checked = Ini.Read("NetWork", "heartHex", false);//s是否采用16进制


        }
        // 接受串口传递数据
        private void SerialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            byte[] bs = new byte[1024]; //定义一个字节数组
            int count = serialPort1.Read(bs, 0, bs.Length); //读取数据到字节数组里面
            if (count == 0)
            {
                //关闭串口
                //停止串口
                if (serialPort1.IsOpen) serialPort1.Close();
                //灭灯
                this.panel1.BackColor = Color.Gray;
            }

            //1 接收到1条串口数据 需要panel3亮一次 封装一个方法控制效果
            jieShouDaoChuankou();

            //2 转发给所有客户端数据 串口转网口就是把串口数据通过网络转给其他客户端 
            foreach (var item in lists)
            {
                item.GetStream().Write(bs, 0, bs.Length);
               
            }
        }
        async void jieShouDaoChuankou()
        {
            this.Invoke((Action)(() =>
            {
                textBox1.Text = (int.Parse(textBox1.Text)+1).ToString();
                //亮灯
                panel3.BackColor = Color.Green;
            }));

            //过一段时间
          await Task.Delay(70);

            this.Invoke((Action)(() =>
            {
               //关灯
                panel3.BackColor = Color.Gray;
            }));

        }

        //波特率下拉框触发变化的时候调用
        private void comboBox2_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (comboBox2.SelectedItem.ToString() == "自定义")
            {
                //切换到自定义选项上
                comboBox2.DropDownStyle= ComboBoxStyle.DropDown;
            }
            else
            {
                comboBox2.DropDownStyle = ComboBoxStyle.DropDownList;
            }
        }

        //选中心跳开关为开的时候
        private void radioButton1_CheckedChanged(object sender, EventArgs e)
        {
            //MessageBox.Show(textBox4.Text + "????/");
            if (radioButton1.Checked)
            {
             
                //选中心跳
                timer1.Interval = string.IsNullOrEmpty(textBox4.Text) ? 2000 : int.Parse(textBox4.Text); 
                timer1.Tick += Timer1_Tick;
                timer1.Start();
            }
        }
        //定时器函数
        private void Timer1_Tick(object sender, EventArgs e)
        {
            //定时发送数据
            string data = textBox5.Text; //心跳数据 2选中hex证明把2转成16进制,
            byte[] buffer;
            if (checkBox1.Checked == true)
            {
                //需要发16进制的心跳
                string[] ds = data.Split(' '); //把2按照空格符号分割成数组结构[2]
                buffer = new byte[ds.Length]; //buffer数组长度就是ds的长度
                for (int i = 0; i < ds.Length; i++)
                {
                    //System.Globalization.NumberStyles.HexNumber 转成16进制数
                    //把ds[i]转成16进制
                    buffer[i] = byte.Parse(ds[i], System.Globalization.NumberStyles.HexNumber);
                }
            }
            else
            {
                //不采用16进制的心跳包
                buffer = Encoding.UTF8.GetBytes(data);
            }
            foreach (var item in lists)
            {
                item.GetStream().Write(buffer, 0, buffer.Length);
            }

        }

        //关闭心跳
        private void radioButton2_CheckedChanged(object sender, EventArgs e)
        {
            timer1.Stop();
        }

        //重启
        private void button1_Click(object sender, EventArgs e)
        {
            //停掉tcp
            foreach (var item in lists)
            {
                item.Close(); //关闭所有的客户端
            }
            listen.Stop();
            panel2.BackColor = Color.Gray;

            //停掉串口
            if (serialPort1.IsOpen) serialPort1.Close();
            //灭灯
            this.panel1.BackColor = Color.Gray;

            //开启tcp
            startTCP();
            //开启串口
            startChuanKou();

        }
        //保存
        private void button2_Click(object sender, EventArgs e)
        {
            //Serialport", "databit", "8");
            Ini.Write("Serialport", "name", comboBox1.Text);
            Ini.Write("Serialport", "botelv", comboBox2.Text);
            Ini.Write("Serialport", "stopbit", comboBox5.SelectedIndex);
            Ini.Write("Serialport", "parity", comboBox4.SelectedIndex);
            Ini.Write("Serialport", "databit", comboBox3.Text);//5 6 7 8 

            Ini.Write("NetWork", "port", textBox3.Text);
            Ini.Write("NetWork", "heartOn",radioButton1.Checked);
            Ini.Write("NetWork", "heartTime", textBox4.Text);
            Ini.Write("NetWork", "heartData", textBox5.Text);
            Ini.Write("NetWork", "heartHex", checkBox1.Checked);
        }
    }
}