网口串口(Serialport)服务器

文章所用工具
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{//不能转成boolif (v=="1"||v=="OK"||v=="ON"||v=="YES"){return true;}else if(v=="0"||v=="NO"||v=="OFF"||v.ToUpper()=="OFF"){//如果值以上几种请求 值为falsereturn 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)
{// 停掉tcpforeach (var item in lists){item.Close(); // 关闭所有的客户端}listen.Stop();panel2.BackColor = Color.Gray;// 停掉窗口if (serialPort1.IsOpen) serialPort1.Close();// 灭灯this.panel1.BackColor = Color.Gray;// 开启tcpstartTCP();// 开启串口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 8Ini.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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/367910.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Qt creator实现一个简单计算器

目录 1 界面设计 2 思路简介 3 代码 目录 1 界面设计 ​2 思路简介 3 代码 3.1 widget.h 3.2 widget.c 4 完整代码 在这里主要记载了如何使用Qt creator完成一个计算器的功能。该计算器可以实现正常的加减乘除以及括号操作&#xff0c;能实现简单的计算器功能。 1 界…

Qt Creator配置以及使用Git

Qt Creator配置以及使用Git 引言一、Qt Creator配置git二、Qt Creator使用git2.1 创建git仓库 or git项目导入Qt2.2 配置远端&#xff0c;拉代码 or 上传代码2.3 查看更改2.4 更多细节可参考官方文档 三、参考的博客以及文档 引言 Qt Creator配置Git之后&#xff0c;可以看作是…

使用Charles实现Android抓包,附带Charles破解教程

1.下载Charles 网址&#xff1a;下载Charles 安装完成后的界面&#xff1a; 2.配置http抓包 点击该选项 可以看到代理的 ip 和端口号 然后在手机的wifi中配置代理&#xff08;手机和电脑要在同一局域网&#xff09;&#xff0c;代理选择手动&#xff0c;并填入ip和端…

vue3中 slot使用

默认插槽&#xff1a; 这是最基本的插槽类型&#xff0c;当没有指定 name 属性时&#xff0c;插槽是默认插槽。 子组件&#xff1a; <template><div class"child"><h2>子组件内容</h2><slot></slot> <!-- 默认插槽&#x…

UnityUGUI之三 Text

富文本 常用语法&#xff1a; 1.加粗 <b> text </b> 2.斜体 <i> text </i> 3.尺寸 <size?> text </size> 4.颜色 <color#ff0000> text </color>

zabbix小白入门:从SNMP配置到图形展示——以IBM服务器为例

作者 乐维社区&#xff08;forum.lwops.cn&#xff09;许远 在运维实践中&#xff0c;Zabbix作为一款强大的开源监控工具&#xff0c;被广泛应用于服务器、网络设备和应用程序的监控&#xff0c;成为保障业务连续性和高效运行的关键。然而&#xff0c;对于Zabbix的初学者来说&a…

发送微信消息和文件

参考&#xff1a;https://www.bilibili.com/video/BV1S84y1m7xd 安装&#xff1a; pip install PyOfficeRobotimport PyOfficeRobotPyOfficeRobot.chat.send_message(who"文件传输助手", message"你好&#xff0c;我是PyOfficeRobot&#xff0c;有什么可以帮助…

泽州县和美环保科技有限公司——绿色环保的践行者

在环保产业蓬勃发展的今天&#xff0c;泽州县和美环保科技有限公司以其卓越的技术和强大的实力&#xff0c;成为山西省危废综合处置领域的翘楚。作为雅居乐环保集团的全资子公司&#xff0c;和美环保科技有限公司紧跟集团发展战略&#xff0c;致力于为社会提供全方位的环境服务…

UE5 04-重新加载当前场景

给关卡加一个淡出的效果 给关卡加一个淡入的效果, 这个最好放置在Player 上,这样切关卡依然有这个效果

Chapter10 高级纹理——Shader入门精要学习笔记

Chapter10 高级纹理 一、立方体纹理1.基本概念①组成②采样 2.天空盒子 Sky Box3.环境映射三种方法①特殊布局的纹理创建②手动创建Cubemap——老方法③脚本生成 4.反射5.折射6.菲涅尔反射 二、渲染1.镜子效果2.玻璃效果3.渲染纹理 vs GrabPass 三、程序纹理1.简单程序纹理2.Un…

Mybatis Plus 自动填充注解 @TableField(fill = FieldFill.INSERT_UPDATE)

第一步&#xff1a;在需要自动填充的位置加上注解 通过在创建时间和修改时间上添加 fill 填充字段 进行自动填充 第二步&#xff1a;要想实现自动填充还需要实现MetaObjectHandler接口&#xff0c;在这里实现自动填充的逻辑 Component public class MyMetaObjectHandler …

Cmake静态库与动态库的构建与使用

项目目录 各个文件 myhell.h // // Created by glt on 2024/7/3. //#ifndef MY_PRO_HELLO_H #define MY_PRO_HELLO_H#include <iostream>void HelloFunc();#endif //MY_PRO_HELLO_Hhello.cpp // // Created by glt on 2024/7/3. // #include "myhello.h"voi…

《数据结构与算法基础 by王卓老师》学习笔记——2.5线性表的链式表示与实现1

1.链式表示 2.链表举例 3.链式存储的相关术语 4.三个讨论题

文本分析-使用Python做词频统计分析

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

【Python机器学习】模型评估与改进——带交叉验证的网格搜索

虽然将数据划分为训练集、验证集、测试集的方法是可行的&#xff0c;也相对常用&#xff0c;但这种方法对数据的划分相当敏感&#xff0c;为了得到对泛化性能的更好估计&#xff0c;我们可以使用交叉验证来评估每种参数组合的性能&#xff0c;而不是仅将数据单次划分为训练集与…

【简单讲解下npm常用命令】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

最靓丽的C++开源通知弹框SnoreToasts自动监听软件及网页通知

SnoreToasts&#xff0c;作为一款轻量级的C开源项目&#xff0c;为开发者提供了一个便捷的方式来在Windows操作系统上展示通知弹框&#xff08;Toast Notifications&#xff09;。 特点与优势 轻量级&#xff1a;SnoreToasts采用了简洁的代码设计&#xff0c;避免了不必要的依…

昇思25天学习打卡营第3天|yulang

今天主要学习03-张量Tensor&#xff0c;主要包含了处理创建张量、张量的属性、张量索引和张量运算&#xff0c;稀疏张量&#xff0c;有点看不太懂&#xff0c;感觉要开始入门到放弃了&#xff1f;张量在构建和训练深度学习模型中的实际应用&#xff0c;如卷积神经网络。 张量&a…

2024 AIGC 技术创新应用研讨会暨数字造型设计师高级研修班通知

尊敬的老师、领导您好! 为深入响应国家关于教育综合改革的战略部署&#xff0c;深化职业教育、高等教育改革&#xff0c;发挥企业主体重要作用&#xff0c;促进人才培养供给侧和产业需求侧结构要素全方位融合&#xff0c;充分把握人工智能创意式生成(AIGC)技术在教育领域的发展…

如何使用代理 IP 防止多个 Facebook 帐户关联 - 最佳实践

在社交媒体被广泛应用的今天&#xff0c;Facebook作为全球最大的社交网络平台之一&#xff0c;面临着很多挑战&#xff0c;其中之一就是用户行为的管理和安全。 为了防止多个账户之间的关联和滥用&#xff0c;Facebook需要采取一系列措施&#xff0c;其中包括使用静态住宅代理…