网口串口(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
    {
        //不能转成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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

理解Netty的核心概念

一、理解Netty Netty是一个用于开发高性能网络应用的框架。为了更容易理解它&#xff0c;下面一些描述&#xff0c;不一定准确&#xff0c;但一定容易理解。 从Netty的Channel开始&#xff0c;把Netty所有的核心概念都串起来。 Channel 简单理解为一个连接。 有一个特殊的C…

python使用pywebview集成vue3和element-plus开发桌面系统框架

随着web技术越来越成熟&#xff0c;就连QQ的windows客户端都用web技术来开发&#xff0c;所以在未来&#xff0c;web技术来开发windows桌面软件也会越来越多&#xff0c;所以在此发展驱动之下&#xff0c;将最近流程的python与web技术相结合&#xff0c;使用vue3和element-plus…

使用requests爬取拉勾网python职位数据

爬虫目的 本文是想通过爬取拉勾网Python相关岗位数据&#xff0c;简单梳理Requests和xpath的使用方法。 代码部分并没有做封装&#xff0c;数据请求也比较简单&#xff0c;所以该项目只是为了熟悉requests爬虫的基本原理&#xff0c;无法用于稳定的爬虫项目。 爬虫工具 这次…

Linux中为什么etc是存放配置文件

在计算机系统中&#xff0c;/etc 是一个目录的名称&#xff0c;通常位于Unix和类Unix操作系统中&#xff0c;如Linux。这个目录用于存放系统配置文件。/etc 的命名来源于早期Unix系统中的 "etcetera"&#xff08;拉丁语 "et cetera" 的缩写&#xff0c;意为…

电子工程与网络技术解析

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;日常聊聊 ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 正文 1、MUX&PD是什么意思 2、Hub 和HUB有什么区别 3、Redriver什么意思 4、Switch是什么意思 5、USB 2.0 ETHERNET2什么意思 6、…

[译]全栈Redux实战

本文乱译自一篇英文博文&#xff08;Full-Stack Redux Tutorial&#xff09;&#xff0c;本人英语能力不足&#xff0c;技术能力有限&#xff0c;如有错误&#xff0c;多多包涵。 #关于ReduxReactImmutable的测试先行开发综合指南 Redux是最近发生在js界令人兴奋的事儿。它把…

Vue+Xterm.js+WebSocket+JSch实现Web Shell终端

一、需求 在系统中使用Web Shell连接集群的登录节点 二、实现 前端使用Vue&#xff0c;WebSocket实现前后端通信&#xff0c;后端使用JSch ssh通讯包。 1. 前端核心代码 <template><div class"shell-container"><div id"shell"/>&l…

Unity动画系统(2)

6.1 动画系统基础2-3_哔哩哔哩_bilibili p316 模型添加Animator组件 动画控制器 AnimatorController AnimatorController 可以通过代码控制动画速度 建立动画间的联系 bool值的设定 trigger p318 trigger点击的时候触发&#xff0c;如喊叫&#xff0c;开枪及换子弹等&#x…

css flex 子元素溢出时,父元素被撑开解决方案

当父元素使用flex: 1;自适应填满时&#xff0c;子元素内容溢出&#xff0c;父元素内容撑大&#xff0c;导致页面显示问题&#xff0c;或设置了overflow 为scroll 的元素没出现滚动条等问题 解决方案&#xff1a; 1.如果是横向排列&#xff0c;flex: 1;的元素加上width: 0; 此…

【PB案例学习笔记】-28制作一个右键菜单

写在前面 这是PB案例学习笔记系列文章的第28篇&#xff0c;该系列文章适合具有一定PB基础的读者。 通过一个个由浅入深的编程实战案例学习&#xff0c;提高编程技巧&#xff0c;以保证小伙伴们能应付公司的各种开发需求。 文章中设计到的源码&#xff0c;小凡都上传到了gite…

流量控制组件选型之 Sentinel vs Hystrix

Sentinel: Sentinel 是阿里中间件团队研发的面向分布式服务架构的轻量级高可用流量控制组件&#xff0c;于2018年7月正式开源。Sentinel 主要以流量为切入点&#xff0c;从流量控制、熔断降级、系统负载保护等多个维度来帮助用户提升服务的稳定性。大家可能会问&#xff1a;Sen…

总线局域网及解决冲突的方案

上文内容&#xff1a;局域网 1.什么是总线局域网 总线网结构&#xff1a; 所有的结点通过专门的网卡附接到一条总线上&#xff1b; 所有结点的信息都发送到同一条总线上&#xff08;冲突&#xff09;&#xff1b; 所有结点都从同一媒体上收取信息&#xff08;广播&am…

视频汇聚/安防监控/GB28181国标EasyCVR视频综合管理平台出现串流的原因排查及解决

安防视频监控系统/视频汇聚EasyCVR视频综合管理平台&#xff0c;采用了开放式的网络结构&#xff0c;能在复杂的网络环境中&#xff08;专网、局域网、广域网、VPN、公网等&#xff09;将前端海量的设备进行统一集中接入与视频汇聚管理&#xff0c;视频汇聚EasyCVR平台支持设备…

Stable Diffusion web UI 插件

2024.7.3更新&#xff0c;持续更新中 如果需要在linux上自己安装sd&#xff0c;参考&#xff1a;stable diffusion linux安装 插件复制到 /stable-diffusion-webui/extensions 目录下&#xff0c;然后重新启动sd即可 一、插件安装方法 每种插件的安装方法可能略有不同&#xf…

Redis分布式锁的应用场景有哪些

⼀ 、应⽤场景 在多线程并发的场景下 &#xff0c;Java Synchronized/Reentrantlock 锁能够实现同⼀个JVM进程内多线程 并发的安全性 &#xff0c;但⽆法保证多个JVM进程实例构成的集群环境在多线程下的安全性。在⼀些业务场景 下需要引⼊分布式锁。 1、缓存击穿 当某个热点缓…

精确计算应用的冷启动耗时

在iOS项目中&#xff0c;冷启动时间是指从用户点击应用图标开始&#xff0c;到应用完全加载并呈现出第一个界面&#xff08;可能需要网络请求必要的数据&#xff09;所花费的时间。这里以 main 函数为界&#xff0c;分为两个时间段&#xff1a; 从用户点击应用图标 ~ invoke m…

深度学习简介-AI(三)

深度学习简介 深度学习简介深度学习例子深度学习训练优化1.随机初始化2.优化损失函数3.优化器选择4.选择/调整模型结构 深度学习常见概念隐含层/中间层随机初始化损失函数导数与梯度优化器Mini Batch/epoch 深度学习训练逻辑图 深度学习简介 深度学习例子 猜数字 A: 我现在心…

24年河南特岗教师招聘流程+报名流程

河南特岗教师报名流程如下 1.登录河南省特岗招聘网 登录河南省特岗招聘网注册账号和密码&#xff0c;账号可以是手机号或者身份证号&#xff0c;密码自己设置 2.注册登录账号 注册完账号重新登录账号&#xff0c;输入身份证号、手机号、密码、验证码 3.浏览考试须知 填写个人信…

Unity Shader技巧:实现带投影机效果,有效避免边缘拉伸问题

这个是原始的projector 投影组件,边缘会有拉伸 经过修改shader 后边缘就没有拉伸了 (实现代码在文章最后) 这个着色器通过检查每个像素的UV坐标是否在定义的边界内,来确定是否应用黑色边框。如果UV坐标处于边缘区域,那么像素颜色会被强制设为黑色,从而在投影图像周围形成一…

JWT入门

JWT与TOKEN JWT&#xff08;JSON Web Token&#xff09;是一种基于 JSON 格式的轻量级安全令牌&#xff0c;通常用于在网络应用间安全地传递信息。而“token”一词则是一个更广泛的术语&#xff0c;用来指代任何形式的令牌&#xff0c;用于在计算机系统中进行身份验证或授权。J…