RFID設備管理C#客戶端學習筆記之3:用指令控制JT-8290A讀寫器

本例中,JT-8290A讀寫器(其資料在百度雲分享中CSharp>捷通開發包目錄下)鏈接到本地路由器以後,可訪問讀寫器的ip地址進行簡單配置(相似路由器第一次設置),主要是將其「服務器地址」參數設置爲實驗的電腦ip地址便可(本機是服務器,讀寫器是客戶,客戶能夠有多個。服務器和客戶必須在同一個子網才能夠通訊)。
數據庫

因此Socket通訊代碼在(http://my.oschina.net/SnifferApache/blog/406563)基礎上修改~~編程

官方文檔中有以下描述:
c#

若是應用程序在執行期間只須要一個線程,請使用下面的方法,這些方法適用於同步操做模式。數組

  • 若是當前使用的是面向鏈接的協議(如 TCP),則服務器可使用 Listen 方法偵聽鏈接。 Accept 方法處理任何傳入的鏈接請求,並返回可用於與遠程主機進行數據通訊的 Socket。 可使用此返回的 Socket 來調用 Send 或 Receive 方法。 若是要指定本地 IP 地址和端口號,請在調用 Listen 方法以前先調用Bind 方法。 若是您但願基礎服務提供程序爲您分配可用端口,請使用端口號 0。 若是但願鏈接到偵聽主機,請調用 Connect 方法。 若要進行數據通訊,請調用 Send 或 Receive 方法。服務器

  • 若是當前使用的是無鏈接協議(如 UDP),則根本不須要偵聽鏈接。 調用 ReceiveFrom 方法可接受任何傳入的數據報。 使用 SendTo 方法可將數據報發送到遠程主機。socket


在本例中Socket通訊流程以下:ide

①服務器端新建Socket實例server_socket(同時綁定指定的IPEndPoint,將server_socket置於偵聽狀態);this

②主程序啓動線程server_thread處理任何傳入的鏈接請求,一旦成功(好比鏈接到客戶R),其返回的Socket實例connSocket即可以看做服務器與客戶R之間的橋樑。spa

③客戶R要作的事情比較簡單,由於只有一個服務器(不用關心RFID讀寫器作了什麼)。那服務器怎麼區分這麼多的客戶呢?接收和發送可能搞混?.net

那咱們就爲每個客戶單獨拋出一個線程來接收消息,發送的時候選擇指定的客戶connSocket就好啦。

好比客戶R的ip地址爲key,該connSocket爲value,添加到Dictionary<string,Socket>實例中,那就能夠方便的操做啦。

廢話不說,上源碼……

一、添加namespace

C#中Socket編程須要以下名稱空間

using System.Net;

using System.Net.Sockets;

using System.Threading;


二、源碼

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);
            }
        }
    }
}


三、源碼的說明

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

②Server線程運行Run()方法到Accept()處會等待客戶請求,新用戶鏈接以後及時更新用戶下拉列表;

③用戶看到的和數據庫存儲的是16進制數字,每一個字節兩個16進制數字,字節之間空格隔開,發送以前要轉成byte數組,byte數組中每一個元素有8bit,恰好容納一個字節,也就是2個16進制數字。

通訊協議採用奇偶校驗,目前用到的指令最後一個字節就是校驗值,不須要再計算校驗結果。因此沒有實現「添加校驗」按鈕的功能。



  運行結果

四、下一步的工做

將識別到的內容添加到數據庫中

利用Timer實時發送指令,並將軟件運行狀態實施寫入log.txt中

添加右下角系統托盤及菜單,利用 Limited Edition for Visual Studio發佈應用程序

相關文章
相關標籤/搜索