RFID设备管理C#客户端学习笔记之3:用指令控制JT-8290A读写器

本例中,JT-8290A读写器(其资料在百度云分享中CSharp>捷通开发包目录下)连接到本地路由器之后,可访问读写器的ip地址进行简单配置(类似路由器第一次设置),主要是将其“服务器地址”参数设置为实验的电脑ip地址即可(本机是服务器,读写器是客户,客户可以有多个。服务器和客户必须在同一个子网才可以通信)。

所以Socket通信代码在(http://my.oschina.net/SnifferApache/blog/406563)基础上修改~~

官方文档中有如下描述:

如果应用程序在执行期间只需要一个线程,请使用下面的方法,这些方法适用于同步操作模式。

  • 如果当前使用的是面向连接的协议(如 TCP),则服务器可以使用 Listen 方法侦听连接。 Accept 方法处理任何传入的连接请求,并返回可用于与远程主机进行数据通信的 Socket。 可以使用此返回的 Socket 来调用 Send 或 Receive 方法。 如果要指定本地 IP 地址和端口号,请在调用 Listen 方法之前先调用Bind 方法。 如果您希望基础服务提供程序为您分配可用端口,请使用端口号 0。 如果希望连接到侦听主机,请调用 Connect 方法。 若要进行数据通信,请调用 Send 或 Receive 方法。

  • 如果当前使用的是无连接协议(如 UDP),则根本不需要侦听连接。 调用 ReceiveFrom 方法可接受任何传入的数据报。 使用 SendTo 方法可将数据报发送到远程主机。


在本例中Socket通信流程如下:

①服务器端新建Socket实例server_socket(同时绑定指定的IPEndPoint,将server_socket置于侦听状态);

②主程序启动线程server_thread处理任何传入的连接请求,一旦成功(比如连接到客户R),其返回的Socket实例connSocket便可以看作服务器与客户R之间的桥梁。

③客户R要做的事情比较简单,因为只有一个服务器(不用关心RFID读写器做了什么)。那服务器怎么区分这么多的客户呢?接收和发送可能搞混?

那我们就为每一个客户单独抛出一个线程来接收消息,发送的时候选择指定的客户connSocket就好啦。

比如客户R的ip地址为key,该connSocket为value,添加到Dictionary<string,Socket>实例中,那就可以方便的操作啦。

废话不说,上源码……

1、添加namespace

C#中Socket编程需要如下名称空间

using System.Net;

using System.Net.Sockets;

using System.Threading;


2、源码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Runtime.Serialization.Formatters.Binary;

namespace Ex02_wifiServer
{
    public partial class MainForm : Form
    {
        private static int server_port = 8899;
        private static string server_ip = "192.168.3.68";
        private static int buffer_size = 1024;
        private static string data = null;
        private static byte[] receiveBytes = new byte[buffer_size];
        Dictionary<string, Socket> dicSocket = new Dictionary<string, Socket>();
        Dictionary<string, Thread> dicThread = new Dictionary<string, Thread>();
        //添加指令列表
        Dictionary<string, string> cmds = new Dictionary<string, string>();
        public MainForm()
        {
            InitializeComponent();
            this.MaximumSize = this.Size;
            this.MinimumSize = this.Size;
            Control.CheckForIllegalCrossThreadCalls = false;
            label1.Text = "在线读写器数:" + Convert.ToString(cb_readerList.Items.Count);
            cb_readerList.Text = "所有读写器";
            data = "等待用户连接……";
            richTextBox1.AppendText(data);
            richTextBox1.Focus();
        }        

        private void MainForm_Load(object sender, EventArgs e)
        {
            //为cb_cmd添加指令
            cmds.Add("设备识别", "A0 03 82 00 DB");
            cmds.Add("复位读头", "A0 03 65 00 F8");
            cmds.Add("停止工作", "A0 03 50 00 0D");
            cmds.Add("关闭继电器", "A0 04 B1 00 00 AB");
            cmds.Add("打开继电器", "A0 04 B1 00 01 AB");
            foreach (var i in cmds)
            {
                this.cb_cmd.Items.Add(i.Key);
            }
            //定义线程开始
            Socket server_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPAddress ipadd = IPAddress.Parse(server_ip);
            IPEndPoint ipe = new IPEndPoint(ipadd, server_port);
            try
            {
                server_socket.Bind(ipe);
                server_socket.Listen(100);
            }
            catch (Exception ee)
            {
                MessageBox.Show(ee.Message);
                return;
            }
            Thread a = new Thread(Run);
            a.IsBackground = true;
            a.Start(server_socket);            
        }
        int count = 0;
        private void Run(object o)
        {
            Socket socket = o as Socket;
            while (count < 100)
            {
                try
                {
                    count++;
                    Debug.WriteLine("客户连接的次数:" + count);
                    //创建一个负责通信用的socket  阻塞窗体的运行
                    Socket connSocket = socket.Accept();

                    string s = connSocket.RemoteEndPoint.ToString();
                    data = "\n" + s + "已连接!";

                    richTextBox1.AppendText(data);
                    richTextBox1.Focus();
                    //ShowMsg(s + ":连接成功");
                    //记录通信用的socket
                    dicSocket.Add(s, connSocket);
                    cb_readerList.Items.Add(s);
                    label1.Text = "在线读写器数:" + Convert.ToString(cb_readerList.Items.Count);
                    //接收消息
                    Thread th = new Thread(RecMsg);
                    th.IsBackground = true;
                    th.Start(connSocket);
                    dicThread.Add(s, th);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                    break;
                }
            }
        }
        void RecMsg(object o)
        {
            Socket connSocket = o as Socket;
            while (true)
            {
                try
                {
                    //接收客户端发送过来的消息
                    byte[] buffer = new byte[1024 * 1024];
                    //num 接收到的实际有效的字节个数
                    int num = connSocket.Receive(buffer);
                    byte[] buff = new byte[num];
                    string str = "";
                    for (int i = 0; i < num; i++)
                    {
                        buff[i] = buffer[i];
                    }
                    foreach (byte item in buff)    //读取Buff中存的数据,转换成显 示的十六进制数
                    {
                        str += item.ToString("X2") + " ";
                    }

                    //string s = Encoding.Default.GetString(buffer, 0, num);
                    if (str != "!!!I want to close!!!")
                    {
                        data = "\n" + connSocket.RemoteEndPoint.ToString() + "返回:" + str;
                        richTextBox1.AppendText(data);
                        richTextBox1.Focus();
                    }
                    else
                    {
                        string m = connSocket.RemoteEndPoint.ToString();
                        MessageBox.Show(m + "已断开");
                        dicSocket.Remove(str);
                        cb_readerList.Items.Remove(m);
                        cb_readerList.Text = "所有读写器";
                        label1.Text = "在线读写器数:" + Convert.ToString(cb_readerList.Items.Count);
                    }
                }
                catch
                {
                    //MessageBox.Show(ex.Message);
                    connSocket.Close();
                    break;
                }
            }
        }
        //重写关闭窗体程序
        protected override void OnClosing(CancelEventArgs e)    
        {
            Environment.Exit(0);
            e.Cancel = true;
        }
        private void btn_send_Click(object sender, EventArgs e)
        {
            try
            {
                string s = cb_readerList.Text;
                Debug.WriteLine("指令:" + cb_cmd.Text);

                byte[] buff = new byte[20];
                string[] str = tb_cmd.Text.Split(' ');
                //将byte数组转化为16进制
                int k = 0;
                foreach (string item in str)
                {
                    if (item.Trim() != "")
                    {
                        buff[k++] = byte.Parse(item, System.Globalization.NumberStyles.HexNumber);
                    }
                }
                Debug.WriteLine("buff的长度:" + k);
                //byte[] sendBytes = Encoding.Default.GetBytes(sendStr);
                if (s != "所有读写器")
                {
                    dicSocket[s].Send(buff, buff.Length, SocketFlags.None);//向客户端发送信息 
                    data = "\n" + "服务器对" + s + "发送:" + tb_cmd.Text + "  " + buff[k].ToString("X2");
                    Debug.WriteLine("data: " + data);                                  
                    richTextBox1.AppendText(data);
                    richTextBox1.Focus();
                }
                else
                    if (cb_readerList.Items.Count == 0)
                        MessageBox.Show("没有读写器连接到!");
                    else
                    {
                        foreach (string i in cb_readerList.Items)
                            dicSocket[cb_readerList.GetItemText(i)].Send(buff, k, 0);
                        data = "\n" + "服务器对所有读写器发送:" + tb_cmd.Text;                        
                        richTextBox1.AppendText(data);
                        richTextBox1.Focus();
                    }
            }
            catch (Exception ex)
            {

                MessageBox.Show(ex.Message);
            }
        }
       

        private void cb_cmd_SelectedIndexChanged(object sender, EventArgs e)
        {
            try
            {
                this.tb_cmd.Text = cmds[this.cb_cmd.SelectedItem.ToString()];
            }
            catch (Exception ex)
            {
                Debug.WriteLine("下拉列表异常:" + ex);
            }
        }
    }
}


3、源码的说明

①绑定下拉列表和TextBox也是使用Dictionary<T1,T2>泛型类;

②Server线程运行Run()方法到Accept()处会等待客户请求,新用户连接之后及时更新用户下拉列表;

③用户看到的和数据库存储的是16进制数字,每个字节两个16进制数字,字节之间空格隔开,发送之前要转成byte数组,byte数组中每个元素有8bit,刚好容纳一个字节,也就是2个16进制数字。

通信协议采用奇偶校验,目前用到的指令最后一个字节就是校验值,不需要再计算校验结果。所以没有实现“添加校验”按钮的功能。



  运行结果

4、下一步的工作

①将识别到的内容添加到数据库中

②利用Timer实时发送指令,并将软件运行状态实施写入log.txt中

③添加右下角系统托盘及菜单,利用 Limited Edition for Visual Studio发布应用程序

你可能感兴趣的:(RFID设备管理C#客户端学习笔记之3:用指令控制JT-8290A读写器)