网口串口(Serialport)服务器

avatar
作者
筋斗云
阅读量:1

文章所用工具
http://t.csdnimg.cn/2gIR8icon-default.png?t=N7T8http://t.csdnimg.cn/2gIR8

搭建服务器界面

操作配置文件保存方式类

         public string FileName {  get; set; }         public IniHelper(string name)          {             this.FileName = name; //在构造函数中给路径赋值         }
1 先导入c语言进行读取操作ini文件的方法

GetPrivateProfileString() 获取ini配置文件的数据
        //static 静态的变量 只能声明在当前文件中,不能在其他源文件进行使用。
        //extern 用来声明外部的符号 可以跨文件使用。

[DllImport("Kernel32.dll")] //导入方法所在dll文件 public static extern Int32 GetPrivateProfileString(     string sectionName, //段名      string keyName,//键名     string defaultName,//当键不存在默认值。     StringBuilder returnValue,// 读取到数据     uint size,// 读取数据的大小     string fileName// ini文件路径     );
2添加写入ini文件的c方法
[DllImport("Kernel32.dll")] public static extern Int32 WritePrivateProfileString(   string sectionName, //段名    string keyName,//键名   string value,//设置的值   string fileName// ini文件路径   );

不直接使用上面的俩个c语言的方法 再封装到其他方法进行使用
        //读取ini数据的方法
        //ReadData("Second","B","Setting.ini") "10"
        //参数1 段名 ,参数2键名 ,参数3是文件路径

public static string ReadData(string sectionName,string keyName,string fileName) {     StringBuilder sb = new StringBuilder(512); //512是存储的大小     GetPrivateProfileString(sectionName, keyName, string.Empty, sb, 512, fileName);     return sb.ToString(); } 

对上面ReadData再封装,封装能直接返回指定类型的数据的方法
        //传进段名和键名获取内容
        //以后Read("段名","键名")  返回字符串类型

public string Read(string sectionName,string keyName) {     return ReadData(sectionName, keyName,this.FileName);  }

如果读取数据 没读取到 给赋一个初值
        Read("Secotion",A,"1000")  最终结果:hello world
        Read("Secotion",C,"1000")  最终结果:1000

 public string Read(string sectionName, string keyName,string defaultValue)  {      string v = Read(sectionName, keyName);      if (string.IsNullOrEmpty(v))      {          return defaultValue;      }      return v;   }

读取的时候 返回一个整型的数据值

Read("Secotion",C,1000)  最终结果:1000
Read("Secotion",A,1000)  最终结果:1000

 

public int Read(string s1, string k1, int d1) {     string v = Read(s1, k1);     if (int.TryParse(v,out int value))     {         return value;     }     else     {         return d1;     }  }
public bool Read(string s1, string k1, bool d1) {     string v = Read(s1, k1);     if (bool.TryParse(v,out bool value))     {         return value;     }     else     {         //不能转成bool         if (v=="1"||v=="OK"||v=="ON"||v=="YES")         {             return true;         }         else if(v=="0"||v=="NO"||v=="OFF"||v.ToUpper()=="OFF")         {             //如果值以上几种请求 值为false             return false;         }         else         {             return d1;         }     } } //ini值是double类型 public double Read(string s1, string k1, double d1) {     string v = Read(s1, k1);     if (double.TryParse(v, out double value))     {         return value;     }     else     {         return d1;     }  }

封装写入数据的方法
先定义一个静态写入方法

public static  int WriteData(string s1,string k1,string v,string file) {     return WritePrivateProfileString(s1,k1,v,file); }

封装方法

//在封装Write方法传递 传进段名 键名 值是字符串 public int Write(string s1,string k1,string v1) {     return WriteData(s1, k1, v1, this.FileName); }  //在封装Write方法传递 传进段名 键名 值是整型 public int Write(string s1, string k1, int v1) {     return WriteData(s1, k1, v1.ToString(), this.FileName); }  //在封装Write方法传递 传进段名 键名 值是bool public int Write(string s1, string k1, bool v1) {     return WriteData(s1, k1, v1?"1":"0", this.FileName); }  //在封装Write方法传递 传进段名 键名 值是时间格式 public int Write(string s1, string k1, DateTime v1) {     return WriteData(s1, k1, v1.ToString("yyyy-MM-dd HH-mm:ss"), this.FileName); }

using调用 

编辑配置文件

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

服务器

 IniHelper Ini;  string[] botelvs = new string[] { "1200", "4800", "9600", "13200" };
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_DataReceivd;  // 3 处理界面显示默认值 也就是从ini文件读取数据 readStting();  // 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 (Exception ex)     {         MessageBox.Show("TCP启动失败");         // 把tcp关闭等操作         foreach(var item  in lists)         {             item.Close(); // 关闭所有的客户端         }         listen.Stop();         panel2.BackColor = Color.Gray;     } }
接收数据
void tcpReceive(TcpClient c1) {          new Task(() =>     {         NetworkStream stream = c1.GetStream();         try         {             MessageBox.Show("111");             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;                 }                 // 把数据转给串口 发送数据,com8能接收到消息,                 serialPort1.Write(bs, 0, length);             }         }         catch         {             c1.Close();             lists.Remove(c1);         }     }).Start(); }
亮灯
async void tcpLiangDeng() {          this.Invoke((Action)(() =>     {         textBox2.Text = (int.Parse(textBox2.Text) + 1).ToString();         // 亮灯         panel4.BackColor = Color.Pink;     }));      // 过一段时间     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 枚举值         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;      }  }  private void readStting() {     // 先配置串口     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;      }     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     {         radioButton1.Checked = true;     }     textBox4.Text = Ini.Read("NetWork", "heartTime", "60000"); // 心跳间隔     textBox5.Text = Ini.Read("NetWork", "heartTime", ""); // 心跳间隔     checkBox1.Checked = Ini.Read("NetWork", "heartTime", false); // 心跳间隔   }
接收串口传递的数据
private void SerialPort1_DataReceivd(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 接收到一条窗口数据 需要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.Pink;     }));      // 过一段时间     await Task.Delay(70);     this.Invoke((Action)(() =>     {         textBox1.Text = (int.Parse(textBox1.Text) + 1).ToString();         // 关灯         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) {          if(radioButton1.Checked)     {         // 选中心跳         timer1.Interval = string.IsNullOrEmpty(textBox4.Text) ? 6000 :  int.Parse(textBox4.Text);         timer1.Tick += Timer1_Tick;         timer1.Start();     } }

定时发送数据
private void Timer1_Tick(object sender, EventArgs e) {     // 定时发送数据     string data = textBox5.Text; // 心跳数据 选中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);     } }
关闭心跳
rivate 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);  }

接受和发送默认值

效果如下

QQ202473-20354

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!