C sharp实例:华盾武器门数据接收和解析

项目介绍:
本实例主要是接收安检金属门的数据解析并显示到界面上,只做功能实现,不做界面美化
硬件:金属门一个、网线一根、电脑主机,金属门网线可以直接接到电脑主机上
开发环境:vs2017 系统:win10
涵盖知识点:tcp通讯、文件写入、多线程,委托、类型转换等

软件操作流程:

点击开始监听按钮,9082要是未被占用则开启监听,然后人通过金属门就可以接收到数据

金属门数据协议截图:

知识点介绍:  1. socket.Listen(10); 官方给出的解释:挂起连接队列的最大长度。 连接队列,即连接池,也就是要保证挂起的连接池中至少要有10个连接                我解释一下,为什么要提前准备10个挂起的连接,原因就是每当一个新用户接入进来时,就需要立即创建一个socket,创建也需要时间和消耗系统资源,这样就会影响高并发的性能                ,用不用,先放那,用的时候直接取即

2. Socket clientSocket = socket.Accept();

AcceptSocket是同步的,你可以用异步通讯的BeginAcceptSocket或者用多线程。没有请求到达,就会“卡”住,术语叫程序阻塞,socket同步通讯就是这个步骤,执行到AcceptSocket就会阻塞等待请求,直到有请求到达时,才执行后面的语句,并且处理这个请求

3. while (true) 因为组要一直监听,所以得死循环;

4. 开启一个后来线程,不然主界面会假死

 new Thread(delegate ()           
  {主体代码;})           
   { IsBackground = true }.Start();

5.从其它线程访问主线程控件需要委托,不然界面不会有数据的 this.Invoke((EventHandler)delegate                        {                            richTextBox1.Text += “”;
                        }); 不完善的地方:金属门每通过一次会发送三条数据,三条数据间有时间间隔,所以为了接收到完整数据我 Thread.Sleep(1000);睡了1秒钟,所以几个人同时通过金属门会有数据丢包,暂时没做相应处理。

完整代码如下:

using System;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Windows.Forms;
using System.IO;
using System.Threading;


namespace TcpRecive
{
    public partial class mainForm : Form
    {
        public mainForm()
        {
            InitializeComponent();
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            textBox1.Text = "9082"; 
        }
        public void tcpRecive(int port)
        {
            if (PortIsUse(port))
            {
                label1.Text = "端口" + port.ToString() + "被占用"; return;
            }
            else label1.Text = "端口" + port.ToString() + "没有占用,监听已开启";
            new Thread(delegate ()
            {
                int recv;//定义接收数据长度变量
                IPAddress ip = IPAddress.Parse("192.168.1.119");//接收端所在IP 192.168.1.119换成127.0.0.1不可以为什么?
                IPEndPoint ipEnd = new IPEndPoint(ip, port);//接收端所监听的接口,ip也可以用IPAddress.Any
                Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//初始化一个Socket对象
                socket.Bind(ipEnd);//绑定套接字到一个IP地址和一个端口上(bind());
                //官方给出的解释:挂起连接队列的最大长度。
                //连接队列,即连接池,也就是要保证挂起的连接池中至少要有10个连接
                //我解释一下,为什么要提前准备10个挂起的连接,原因就是每当一个新用户接入进来时,就需要立即创建一个socket,创建也需要时间和消耗系统资源,这样就会影响高并发的性能
                //,用不用,先放那,用的时候直接取即可
                socket.Listen(10);
                while (true)
                {
                    try
                    {
                        byte[] data = new byte[1024];//对data清零
                        //for (int i = 0; i < data.Length; i++) { data[i] = 0; }
                        Socket clientSocket = socket.Accept(); //一旦接受连接,创建一个客户端
                        Thread.Sleep(1000);//不延时收不到完整数据,可能是三组数据间有时间间隔
                        recv = clientSocket.Receive(data);// 或者clientSocket.Receive(data, data.Length, SocketFlags.None);获取收到的数据的长度
                        if (recv == 0) //如果收到的数据长度小于0,则退出
                            break;
                        //string stringData = Encoding.UTF8.GetString(data);
                        //string stringData = byteToHexStr(data);
                        //MessageBox.Show( dataDecode(data).ToString());
                        //dataDecode(data);
                        string stringData = "0x"+BitConverter.ToString(data, recv-32,32).Replace("-", " 0x").ToLower();//只取最后32个字节的数据
                        //string stringData = Encoding.ASCII.GetString(data);
                        this.Invoke((EventHandler)delegate
                        {
                            richTextBox1.Text += DateTime.Now.ToString("yy-MM-dd hh:mm:ss") + "  安检人数:" + dataDecode(data, 0, recv)
                                                 + "  报警人数:" + dataDecode(data, 1, recv) + "  报警信息:" + alarmPosition(data, recv)
                                                 + "\n" + stringData + "\n";
                        });
                        fileWrite(DateTime.Now.ToString("yy-MM-dd hh:mm:ss") + "\n" + stringData);
                    }
                    catch { };
                }
            })
            { IsBackground = true }.Start();
        }
        /// <summary>
        /// 字节数组转16进制字符串
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static string byteToHexStr(byte[] bytes)
        {
            string returnStr = "";
            if (bytes != null)
            {
                for (int i = 0; i < bytes.Length; i++)
                {
                    returnStr += bytes[i].ToString("X2");
                }
            }
            return returnStr;
        }
        public int dataDecode(byte[] data, int type,int dataLength)
        {
            int personNum = 0;
            switch (type)
            {
                case 0:
                     personNum = Convert.ToInt32(BitConverter.ToString(data, dataLength-27, 4).Replace("-", ""), 16); break; //取出对应位置连续四个字节并转换为通过人数
                case 1:
                     personNum = Convert.ToInt32(BitConverter.ToString(data, dataLength-23, 4).Replace("-", ""), 16); break; //取出对应位置连续四个字节并转换为报警人数                  
                default:; break;
            }
            return personNum;
        }
        public string alarmPosition(byte[] bytes, int dataLength)
        {
            string alarmStr = "";
            for(int i=0;i<10;i++)
            {
                if (bytes[dataLength + i - 19] == 0x00)
                    continue;//0x00则退出本次循环
                switch (bytes[dataLength+i-19])
                {
                    case 0x01: alarmStr = "区位" + (i + 1).ToString() +"工具刀枪"; break;
                    case 0x02: alarmStr = "区位" + (i + 1).ToString() + "马口铁罐体"; break;
                    case 0x03: alarmStr = "区位" + (i + 1).ToString() + "铝制易拉罐"; break;
                    case 0x04: alarmStr = "区位" + (i + 1).ToString() + "违禁品混合"; break;
                    case 0x05: alarmStr = "区位" + (i + 1).ToString() + "铜制铝制管体"; break;
                    case 0x09: alarmStr = "区位" + (i + 1).ToString() + "手机手表"; break;
                    case 0x0a: alarmStr = "区位" + (i + 1).ToString() + "全金属报警"; break;
                    case 0X30: alarmStr = "区位" + (i + 1).ToString() + "非磁性枪支"; break;
                    default: alarmStr = ""; break;
                }
            }
            if (alarmStr == "")
                return "无报警";
            else return alarmStr;
        }
        public void fileWrite(string str)
        {
            if (!File.Exists("info.txt"))
                File.Create("info.txt").Close();//创建文件并关闭
            StreamWriter sw = new StreamWriter("info.txt",true);//向文件追加数据
            sw.WriteLine(str);
            sw.Close();
        }
        //通过 IPGlobalProperties来获取本机的网络连接的信息,并通过GetActiveTcpListeners找到已用端口,进而可以知道所需的端口是否已被占用
        public static bool PortIsUse(int port)
         {
             bool isUse = false;
             IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
             IPEndPoint[] ipEndPoints = ipProperties.GetActiveTcpListeners();//找到已用端口
             foreach (IPEndPoint endPoint in ipEndPoints)
             {
                 if (endPoint.Port == port)//判断是否存在
                 {
                     isUse= true;
                     break;
                 }
             }
             return isUse;
         }
        private void button1_Click(object sender, EventArgs e)
        {
            tcpRecive(int.Parse(textBox1.Text));
        }
    }
}


运行结果:

以上代码完全纯手工打造,如果有疑问欢迎留言,喜欢的小伙伴们可以多多分享,让更多志同道合的伙伴们加入我们的微信交流群一起学习、进步!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值