网口串口(Serialport)服务器

打印 上一主题 下一主题

主题 1048|帖子 1048|积分 3144

文章所用工具
http://t.csdnimg.cn/2gIR8
http://t.csdnimg.cn/2gIR8




搭建服务器界面


利用配置文件生存方式类

  1.         public string FileName {  get; set; }
  2.         public IniHelper(string name)
  3.         {
  4.             this.FileName = name; //在构造函数中给路径赋值
  5.         }
复制代码
1 先导入c语言进行读取利用ini文件的方法

   GetPrivateProfileString() 获取ini配置文件的数据
        //static 静态的变量 只能声明在当前文件中,不能在其他源文件进行使用。
        //extern 用来声明外部的符号 可以跨文件使用。
  1. [DllImport("Kernel32.dll")] //导入方法所在dll文件
  2. public static extern Int32 GetPrivateProfileString(
  3.     string sectionName, //段名
  4.     string keyName,//键名
  5.     string defaultName,//当键不存在默认值。
  6.     StringBuilder returnValue,// 读取到数据
  7.     uint size,// 读取数据的大小
  8.     string fileName// ini文件路径
  9.     );
复制代码
2添加写入ini文件的c方法

  1. [DllImport("Kernel32.dll")]
  2. public static extern Int32 WritePrivateProfileString(
  3.   string sectionName, //段名
  4.   string keyName,//键名
  5.   string value,//设置的值
  6.   string fileName// ini文件路径
  7.   );
复制代码
不直接使用上面的俩个c语言的方法 再封装到其他方法进行使用
        //读取ini数据的方法
        //ReadData("Second","B","Setting.ini") "10"
        //参数1 段名 ,参数2键名 ,参数3是文件路径
  1. public static string ReadData(string sectionName,string keyName,string fileName)
  2. {
  3.     StringBuilder sb = new StringBuilder(512); //512是存储的大小
  4.     GetPrivateProfileString(sectionName, keyName, string.Empty, sb, 512, fileName);
  5.     return sb.ToString();
  6. }
复制代码
对上面ReadData再封装,封装能直接返回指定范例的数据的方法
        //传进段名和键名获取内容
        //以后Read("段名","键名")  返回字符串范例
  1. public string Read(string sectionName,string keyName)
  2. {
  3.     return ReadData(sectionName, keyName,this.FileName);
  4. }
复制代码
  假如读取数据 没读取到 给赋一个初值
        Read("Secotion",A,"1000")  终极结果:hello world
        Read("Secotion",C,"1000")  终极结果:1000
  1. public string Read(string sectionName, string keyName,string defaultValue)
  2. {
  3.      string v = Read(sectionName, keyName);
  4.      if (string.IsNullOrEmpty(v))
  5.      {
  6.          return defaultValue;
  7.      }
  8.      return v;
  9. }
复制代码
读取的时间 返回一个整型的数据值
   Read("Secotion",C,1000)  终极结果:1000
Read("Secotion",A,1000)  终极结果:1000
   
  1. public int Read(string s1, string k1, int d1)
  2. {
  3.     string v = Read(s1, k1);
  4.     if (int.TryParse(v,out int value))
  5.     {
  6.         return value;
  7.     }
  8.     else
  9.     {
  10.         return d1;
  11.     }
  12. }
复制代码
  1. public bool Read(string s1, string k1, bool d1)
  2. {
  3.     string v = Read(s1, k1);
  4.     if (bool.TryParse(v,out bool value))
  5.     {
  6.         return value;
  7.     }
  8.     else
  9.     {
  10.         //不能转成bool
  11.         if (v=="1"||v=="OK"||v=="ON"||v=="YES")
  12.         {
  13.             return true;
  14.         }
  15.         else if(v=="0"||v=="NO"||v=="OFF"||v.ToUpper()=="OFF")
  16.         {
  17.             //如果值以上几种请求 值为false
  18.             return false;
  19.         }
  20.         else
  21.         {
  22.             return d1;
  23.         }
  24.     }
  25. }
  26. //ini值是double类型
  27. public double Read(string s1, string k1, double d1)
  28. {
  29.     string v = Read(s1, k1);
  30.     if (double.TryParse(v, out double value))
  31.     {
  32.         return value;
  33.     }
  34.     else
  35.     {
  36.         return d1;
  37.     }
  38. }
复制代码
封装写入数据的方法
先界说一个静态写入方法
  1. public static  int WriteData(string s1,string k1,string v,string file)
  2. {
  3.     return WritePrivateProfileString(s1,k1,v,file);
  4. }
复制代码
封装方法
  1. //在封装Write方法传递 传进段名 键名 值是字符串
  2. public int Write(string s1,string k1,string v1)
  3. {
  4.     return WriteData(s1, k1, v1, this.FileName);
  5. }
  6. //在封装Write方法传递 传进段名 键名 值是整型
  7. public int Write(string s1, string k1, int v1)
  8. {
  9.     return WriteData(s1, k1, v1.ToString(), this.FileName);
  10. }
  11. //在封装Write方法传递 传进段名 键名 值是bool
  12. public int Write(string s1, string k1, bool v1)
  13. {
  14.     return WriteData(s1, k1, v1?"1":"0", this.FileName);
  15. }
  16. //在封装Write方法传递 传进段名 键名 值是时间格式
  17. public int Write(string s1, string k1, DateTime v1)
  18. {
  19.     return WriteData(s1, k1, v1.ToString("yyyy-MM-dd HH-mm:ss"), this.FileName);
  20. }
复制代码
using调用 


编辑配置文件


存入File文件夹中,放到Dubug文件夹中

服务器

  1. IniHelper Ini;
  2. string[] botelvs = new string[] { "1200", "4800", "9600", "13200" };
复制代码
1 读取配置文件

  1. string dirPath = Path.Combine(Application.StartupPath, "File"); // debug/File
  2. string filePath = Path.Combine(dirPath, "Setting.ini");// debug / file/setting.ini
  3. Ini = new IniHelper(filePath); // 创建读取对象
  4. // 添加串口
  5. comboBox1.Items.AddRange(SerialPort.GetPortNames()); // 获取所有串口 拼接在下拉框的items中
  6. comboBox2.Items.AddRange(botelvs); // 添加波特率数组
  7. comboBox2.Items.Add("自定义");// 添加一个
  8. comboBox3.Items.AddRange(new string[] { "5", "6", "7", "8" });
  9. comboBox4.Items.AddRange(new string[] { "无", "奇校检", "偶校检" });
  10. comboBox5.Items.AddRange(new string[] { "无", "1", "2", "1.5" });
  11. // 2 开始处理逻辑串口接收数据的事件
  12. // 处理串口的数据
  13. this.serialPort1.DataReceived += SerialPort1_DataReceivd;
  14. // 3 处理界面显示默认值 也就是从ini文件读取数据
  15. readStting();
  16. // 4 开始串口通信
  17. startChuanKou();
  18. // 5 开始网口通信
  19. startTCP();
复制代码
开始搭建TCP 服务器

  1. TcpListener listen;
  2. List<TcpClient> lists = new List<TcpClient>(); // 存放所有的客户端
  3. void startTCP()
  4. {
  5.     if(!int.TryParse(textBox3.Text,out int port)||port < 1 || port > 65563)
  6.     {
  7.         MessageBox.Show("请输入正确的端口号");
  8.     }
  9.     // 开启服务器 接受客户端
  10.     try
  11.     {
  12.         listen = new TcpListener(System.Net.IPAddress.Any, port);
  13.         listen.Start(100); // 开始监听
  14.         panel2.BackColor = Color.Green;
  15.         // 把多个客户端接收到数组里面
  16.         new Task(() =>
  17.         {
  18.             try
  19.             {
  20.                 while (true)
  21.                 {
  22.                     // 接受客户端
  23.                     TcpClient c1 = listen.AcceptTcpClient();
  24.                     // 把客户端添加到数组里面 群发需要
  25.                     lists.Add(c1);
  26.                     // 接受客户端发来的消息
  27.                     tcpReceive(c1);
  28.                 }
  29.             }
  30.             catch
  31.             {
  32.                 MessageBox.Show("TCP服务器关闭");
  33.             }
  34.         }).Start();
  35.     }
  36.     catch (Exception ex)
  37.     {
  38.         MessageBox.Show("TCP启动失败");
  39.         // 把tcp关闭等操作
  40.         foreach(var item  in lists)
  41.         {
  42.             item.Close(); // 关闭所有的客户端
  43.         }
  44.         listen.Stop();
  45.         panel2.BackColor = Color.Gray;
  46.     }
  47. }
复制代码
吸收数据

  1. void tcpReceive(TcpClient c1)
  2. {
  3.    
  4.     new Task(() =>
  5.     {
  6.         NetworkStream stream = c1.GetStream();
  7.         try
  8.         {
  9.             MessageBox.Show("111");
  10.             while (c1.Connected) // 当客户端链接的时候
  11.             {
  12.             
  13.                 byte[] bs = new byte[1024];
  14.                 int length = stream.Read(bs, 0, bs.Length);
  15.                 if (length == 0) throw new Exception(); // 客户端断了
  16.                 // 接收到数据亮灯
  17.                 tcpLiangDeng();
  18.                
  19.                 // 把数据转给串口
  20.                 if (!serialPort1.IsOpen)
  21.                 {
  22.                     MessageBox.Show("串口关闭");
  23.                     break;
  24.                 }
  25.                 // 把数据转给串口 发送数据,com8能接收到消息,
  26.                 serialPort1.Write(bs, 0, length);
  27.             }
  28.         }
  29.         catch
  30.         {
  31.             c1.Close();
  32.             lists.Remove(c1);
  33.         }
  34.     }).Start();
  35. }
复制代码
亮灯

  1. async void tcpLiangDeng()
  2. {
  3.    
  4.     this.Invoke((Action)(() =>
  5.     {
  6.         textBox2.Text = (int.Parse(textBox2.Text) + 1).ToString();
  7.         // 亮灯
  8.         panel4.BackColor = Color.Pink;
  9.     }));
  10.     // 过一段时间
  11.     await Task.Delay(70);
  12.     this.Invoke((Action)(() =>
  13.     {
  14.         // 关灯
  15.         panel4.BackColor = Color.Gray;
  16.     }));
  17. }
复制代码
配置串口对象

  1. void startChuanKou()
  2. {
  3.     // 配置串口对象
  4.     try
  5.     {
  6.         this.serialPort1.PortName = comboBox1.Text;// 配置串口名称
  7.         this.serialPort1.BaudRate = int.Parse(comboBox2.Text); // 波特率
  8.         this.serialPort1.DataBits = int.Parse(comboBox3.Text);
  9.         this.serialPort1.StopBits = (StopBits)comboBox5.SelectedIndex; // 正常赋值 StopBits.NOne 枚举值
  10.         this.serialPort1.Parity = (Parity)comboBox4.SelectedIndex; //
  11.         this.serialPort1.Open();
  12.         // 亮灯
  13.         this.panel1.BackColor = Color.Green;
  14.     }
  15.     catch
  16.     {
  17.         MessageBox.Show("打开串口失败");
  18.         // 停止串口
  19.         if(serialPort1.IsOpen) serialPort1.Close();
  20.         // 灭灯
  21.         this.panel1.BackColor = Color.Gray;
  22.     }
  23. }
  24. private void readStting()
  25. {
  26.     // 先配置串口
  27.     comboBox1.SelectedItem = Ini.Read("Serialport", "name", "");
  28.     string botelv = Ini.Read("Serialport", "botelv", "9601");
  29.     int botelvIndex = Array.IndexOf(botelvs, botelv); // 获取botelv在数组里面的索引值
  30.     if (botelvIndex != -1)
  31.     {
  32.         comboBox2.SelectedIndex = botelvIndex;
  33.     }
  34.     else
  35.     {
  36.         // 波特率在数组里面 自定义波特率情况
  37.         comboBox2.DropDownStyle = ComboBoxStyle.DropDown; // 可编辑的下拉框
  38.         // DropDownList 不可编辑的下拉框
  39.         comboBox2.Text = botelv;
  40.     }
  41.     // 处理数据位
  42.     comboBox3.SelectedItem = Ini.Read("Serialport", "databit", "8");
  43.     // 处理奇偶校检位
  44.     comboBox4.SelectedIndex = Ini.Read("Serialport", "parity", 0);
  45.     comboBox5.SelectedIndex = Ini.Read("Serialport", "stopbit", 0);
  46.     comboBox1.DropDownStyle = ComboBoxStyle.DropDownList;
  47.     comboBox3.DropDownStyle = ComboBoxStyle.DropDownList;
  48.     comboBox4.DropDownStyle = ComboBoxStyle.DropDownList;
  49.     comboBox5.DropDownStyle = ComboBoxStyle.DropDownList;
  50.     // 网口数据的读取
  51.     textBox3.Text = Ini.Read("NetWork", "port", "8080");
  52.     if (Ini.Read("NetWork", "heartOn", false))
  53.     {
  54.         radioButton1.Checked = true;
  55.     }
  56.     else
  57.     {
  58.         radioButton1.Checked = true;
  59.     }
  60.     textBox4.Text = Ini.Read("NetWork", "heartTime", "60000"); // 心跳间隔
  61.     textBox5.Text = Ini.Read("NetWork", "heartTime", ""); // 心跳间隔
  62.     checkBox1.Checked = Ini.Read("NetWork", "heartTime", false); // 心跳间隔
  63. }
复制代码
吸收串口通报的数据

  1. private void SerialPort1_DataReceivd(object sender, SerialDataReceivedEventArgs e)
  2. {
  3.     byte[] bs = new byte[1024]; // 定义一个字节数组
  4.     int count = serialPort1.Read(bs,0,bs.Length); // 读取数据到字节数组
  5.     if(count == 0)
  6.     {
  7.         // 关闭窗口
  8.         // 停止串口
  9.         if (serialPort1.IsOpen) serialPort1.Close();
  10.         // 灭灯
  11.         this.panel1.BackColor = Color.Gray;
  12.     }
  13.     // 1 接收到一条窗口数据 需要panel3亮一次 分装一个方法控制效果
  14.     JieShouDaoChuanKou();
  15.     // 2 转发给所有的客户端发消息 串口转网口就是把串口数据通过网络转给其他客户端
  16.     foreach(var item in lists)
  17.     {
  18.         item.GetStream().Write(bs,0,bs.Length);
  19.     }
  20. }
  21. async void JieShouDaoChuanKou()
  22. {
  23.     this.Invoke((Action)(() =>
  24.     {
  25.         textBox1.Text = (int.Parse(textBox1.Text) + 1).ToString();
  26.         // 亮灯
  27.         panel3.BackColor = Color.Pink;
  28.     }));
  29.     // 过一段时间
  30.     await Task.Delay(70);
  31.     this.Invoke((Action)(() =>
  32.     {
  33.         textBox1.Text = (int.Parse(textBox1.Text) + 1).ToString();
  34.         // 关灯
  35.         panel3.BackColor = Color.Gray;
  36.     }));
  37. }
复制代码
波特率下拉框出发变化的时间调用

  1. private void comboBox2_SelectedIndexChanged(object sender, EventArgs e)
  2. {
  3.     if(comboBox2.SelectedItem.ToString() == "自定义")
  4.     {
  5.         // 切换到自定义选项上
  6.         comboBox2.DropDownStyle = ComboBoxStyle.DropDown;
  7.     }
  8.     else
  9.     {
  10.         comboBox2.DropDownStyle = ComboBoxStyle.DropDownList;
  11.     }
  12. }
复制代码
选中央跳开关为开的时间

  1. private void radioButton1_CheckedChanged(object sender, EventArgs e)
  2. {
  3.    
  4.     if(radioButton1.Checked)
  5.     {
  6.         // 选中心跳
  7.         timer1.Interval = string.IsNullOrEmpty(textBox4.Text) ? 6000 :  int.Parse(textBox4.Text);
  8.         timer1.Tick += Timer1_Tick;
  9.         timer1.Start();
  10.     }
  11. }
复制代码

定时发送数据

  1. private void Timer1_Tick(object sender, EventArgs e)
  2. {
  3.     // 定时发送数据
  4.     string data = textBox5.Text; // 心跳数据 选中hex整明把2转成16进制,
  5.     byte[] buffer;
  6.     if(checkBox1.Checked == true)
  7.     {
  8.         // 需要发16进制的心跳
  9.         string[] ds = data.Split(' '); //把2按照空格符号分割成数组结构[2]
  10.         buffer = new byte[ds.Length]; // buffer数组长度就是ds的长度
  11.         for(int i = 0; i < ds.Length; i++)
  12.         {
  13.             // System.Globalization.NumberStyles.HexNumber); 转成16进制数
  14.             // 把ds[i]转成16进制
  15.             buffer[i] = byte.Parse(ds[i],System.Globalization.NumberStyles.HexNumber);
  16.         }
  17.     }
  18.     else
  19.     {
  20.         // 不采用16进制的心跳包
  21.         buffer = Encoding.UTF8.GetBytes(data);
  22.     }
  23.     foreach(var item in lists)
  24.     {
  25.         item.GetStream().Write(buffer, 0, buffer.Length);
  26.     }
  27. }
复制代码
关闭心跳

  1. rivate void radioButton2_CheckedChanged(object sender, EventArgs e)
  2.         {
  3.             timer1.Stop();
  4.         }
复制代码
重启

  1. private void button1_Click(object sender, EventArgs e)
  2. {
  3.     // 停掉tcp
  4.     foreach (var item in lists)
  5.     {
  6.         item.Close(); // 关闭所有的客户端
  7.     }
  8.     listen.Stop();
  9.     panel2.BackColor = Color.Gray;
  10.     // 停掉窗口
  11.     if (serialPort1.IsOpen) serialPort1.Close();
  12.     // 灭灯
  13.     this.panel1.BackColor = Color.Gray;
  14.     // 开启tcp
  15.     startTCP();
  16.     // 开启串口
  17.     startChuanKou();
  18. }
复制代码
生存

  1. private void button2_Click(object sender, EventArgs e)
  2. {
  3.     // "Serialport", "databit","8");
  4.     Ini.Write("Serialport","name",comboBox1.Text);
  5.     Ini.Write("Serialport", "botelv", comboBox2.Text);
  6.     Ini.Write("Serialport", "stopbit", comboBox5.SelectedIndex);
  7.     Ini.Write("Serialport", "parity", comboBox4.SelectedIndex);
  8.     Ini.Write("Serialport", "databit", comboBox3.Text); // 5 6 7 8
  9.     Ini.Write("NetWork", "port", textBox3.Text);
  10.     Ini.Write("NetWork", "heartOn", radioButton1.Checked);
  11.     Ini.Write("NetWork", "heartTime", textBox4.Text);
  12.     Ini.Write("NetWork", "heartData", textBox5.Text);
  13.     Ini.Write("NetWork", "heartHex", checkBox1.Checked);
  14. }
复制代码
担当和发送默认值


效果如下
     QQ202473-20354

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

嚴華

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表