背景:Vue調用硬件比較麻煩,通過明華讀卡器讀取IC卡的數據,封裝成一個HTTP,其他人只需要調用HTTP就可以讀取IC卡。
Demo效果圖:
一.c# 通過HttpListener創建HTTP服務
在c#中可以利用HttpListener來自定義創建HTTP服務,通過http協議進行服務端與多個客戶端之間的信息傳遞,並且可以做成windows系統服務,而不用寄宿在IIS上。
二.使用明華讀卡器,需要把mwrf32.dll放在在根目錄里(與.exe同一目錄,可去官網下載)
1.讀IC卡數據需要五步
連接讀卡器、加載密碼,此密碼是用來驗證卡片的密碼、尋卡、驗證密碼、讀數據
2.一片對應四區,如果密碼驗證錯誤就會讀不出數據,比如2對應8
var stcode = rf_authentication(icdev, 0, 2); //驗證密碼
var st = rf_read_hex(icdev, 8, databuffer); //讀數據
三、源碼
public partial class MainWindow : Window { //變量 public static IntPtr icdev = IntPtr.Zero; static HttpListener httpobj; //static byte sector; //扇區號 public static string msg; public static string msg2; public static string msg3; public static string msg4; public MainWindow() { InitializeComponent(); //提供一個簡單的、可通過編程方式控制的 HTTP 協議偵聽器。此類不能被繼承。 httpobj = new HttpListener(); //定義url及端口號,通常設置為配置文件 httpobj.Prefixes.Add("http://127.0.0.1/ReadIC/"); //啟動監聽器 httpobj.Start(); //異步監聽客戶端請求,當客戶端的網絡請求到來時會自動執行Result委托 //該委托沒有返回值,有一個IAsyncResult接口的參數,可通過該參數獲取context對象 httpobj.BeginGetContext(Result, null); bt1_Click(); } private static void Result(IAsyncResult ar) { //當接收到請求后程序流會走到這里 //繼續異步監聽 httpobj.BeginGetContext(Result, null); var guid = Guid.NewGuid().ToString(); Console.ForegroundColor = ConsoleColor.White; Console.WriteLine($"接到新的請求:{guid},時間:{DateTime.Now.ToString()}"); //獲得context對象 var context = httpobj.EndGetContext(ar); var request = context.Request; var response = context.Response; ////如果是js的ajax請求,還可以設置跨域的ip地址與參數 //context.Response.AppendHeader("Access-Control-Allow-Origin", "*");//后台跨域請求,通常設置為配置文件 //context.Response.AppendHeader("Access-Control-Allow-Headers", "ID,PW");//后台跨域參數設置,通常設置為配置文件 //context.Response.AppendHeader("Access-Control-Allow-Method", "post");//后台跨域請求設置,通常設置為配置文件 context.Response.ContentType = "text/plain;charset=UTF-8";//告訴客戶端返回的ContentType類型為純文本格式,編碼為UTF-8 context.Response.AddHeader("Content-type", "text/plain;charset=UTF-8");//添加響應頭信息 context.Response.ContentEncoding = Encoding.UTF8; string returnObj = null;//定義返回客戶端的信息 if (request.HttpMethod == "POST" && request.InputStream != null) { //處理客戶端發送的請求並返回處理信息 returnObj = HandleRequest(request, response); } else { bt2_Click(); bt3_Click(); bt4_Click(); returnObj = msg + "\r\n" + msg2 + "\r\n" + msg3 + "\r\n" + msg4; } var returnByteArr = Encoding.UTF8.GetBytes(returnObj);//設置客戶端返回信息的編碼 try { using (var stream = response.OutputStream) { //把處理信息返回到客戶端 stream.Write(returnByteArr, 0, returnByteArr.Length); } } catch (Exception ex) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine($"網絡蹦了:{ex.ToString()}"); } Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine($"請求處理完成:{guid},時間:{ DateTime.Now.ToString()}\r\n"); } private static string HandleRequest(HttpListenerRequest request, HttpListenerResponse response) { string data = null; try { var byteList = new List<byte>(); var byteArr = new byte[2048]; int readLen = 0; int len = 0; //接收客戶端傳過來的數據並轉成字符串類型 do { readLen = request.InputStream.Read(byteArr, 0, byteArr.Length); len += readLen; byteList.AddRange(byteArr); } while (readLen != 0); data = Encoding.UTF8.GetString(byteList.ToArray(), 0, len); //獲取得到數據data可以進行其他操作 } catch (Exception ex) { response.StatusDescription = "404"; response.StatusCode = 404; Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine($"在接收數據時發生錯誤:{ex.ToString()}"); return $"在接收數據時發生錯誤:{ex.ToString()}";//把服務端錯誤信息直接返回可能會導致信息不安全,此處僅供參考 } response.StatusDescription = "200";//獲取或設置返回給客戶端的 HTTP 狀態代碼的文本說明。 response.StatusCode = 200;// 獲取或設置返回給客戶端的 HTTP 狀態代碼。 Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine($"接收數據完成:{data.Trim()},時間:{DateTime.Now.ToString()}"); return $"接收數據完成"; } [DllImport("mwrf32.dll", EntryPoint = "rf_init", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)] public static extern IntPtr rf_init(Int16 port, int baud); [DllImport("mwrf32.dll", EntryPoint = "usb_init", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)] public static extern IntPtr usb_init(); [DllImport("mwrf32.dll", EntryPoint = "rf_exit", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)] public static extern Int16 rf_exit(IntPtr icdev); [DllImport("mwrf32.dll", EntryPoint = "rf_beep", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)] public static extern Int16 rf_beep(IntPtr icdev, int msec); [DllImport("mwrf32.dll", EntryPoint = "rf_get_status", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)] public static extern Int16 rf_get_status(IntPtr icdev, byte[] state); [DllImport("mwrf32.dll", EntryPoint = "rf_load_key", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)] public static extern Int16 rf_load_key(IntPtr icdev, byte mode, byte secnr, byte[] keybuff); [DllImport("mwrf32.dll", EntryPoint = "rf_load_key_hex", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)] public static extern Int16 rf_load_key_hex(IntPtr icdev, byte mode, byte secnr, byte[] keybuff); [DllImport("mwrf32.dll", EntryPoint = "a_hex", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)] public static extern Int16 a_hex(byte[] asc, byte[] hex, Int16 len); [DllImport("mwrf32.dll", EntryPoint = "hex_a", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)] public static extern Int16 hex_a(byte[] hex, byte[] asc, Int16 len); [DllImport("mwrf32.dll", EntryPoint = "rf_reset", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)] public static extern Int16 rf_reset(IntPtr icdev, Int16 msec); [DllImport("mwrf32.dll", EntryPoint = "rf_request", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)] public static extern Int16 rf_request(IntPtr icdev, byte mode, out UInt16 tagtype); [DllImport("mwrf32.dll", EntryPoint = "rf_anticoll", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)] public static extern Int16 rf_anticoll(IntPtr icdev, byte bcnt, out UInt32 snr); [DllImport("mwrf32.dll", EntryPoint = "rf_select", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)] public static extern Int16 rf_select(IntPtr icdev, UInt32 snr, out byte size); [DllImport("mwrf32.dll", EntryPoint = "rf_card", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)] public static extern Int16 rf_card(IntPtr icdev, byte mode, byte[] snr); //這里將第三個參數設置為byte數組,以便直接返回16進制卡號 //public static extern Int16 rf_card(IntPtr icdev, int mode, out UInt32 snr); [DllImport("mwrf32.dll", EntryPoint = "rf_authentication", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)] public static extern Int16 rf_authentication(IntPtr icdev, byte mode, byte secnr); [DllImport("mwrf32.dll", EntryPoint = "rf_authentication_2", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)] public static extern Int16 rf_authentication_2(IntPtr icdev, byte mode, byte keynr, byte blocknr); [DllImport("mwrf32.dll", EntryPoint = "rf_read", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)] public static extern Int16 rf_read(IntPtr icdev, byte blocknr, byte[] databuff); [DllImport("mwrf32.dll", EntryPoint = "rf_read_hex", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)] public static extern Int16 rf_read_hex(IntPtr icdev, byte blocknr, byte[] databuff); [DllImport("mwrf32.dll", EntryPoint = "rf_write_hex", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)] public static extern Int16 rf_write_hex(IntPtr icdev, int blocknr, byte[] databuff); [DllImport("mwrf32.dll", EntryPoint = "rf_write", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)] public static extern Int16 rf_write(IntPtr icdev, byte blocknr, byte[] databuff); [DllImport("mwrf32.dll", EntryPoint = "rf_halt", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)] public static extern Int16 rf_halt(IntPtr icdev); [DllImport("mwrf32.dll", EntryPoint = "rf_changeb3", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)] public static extern Int16 rf_changeb3(IntPtr icdev, byte sector, byte[] keya, byte B0, byte B1, byte B2, byte B3, byte Bk, byte[] keyb); [DllImport("mwrf32.dll", EntryPoint = "rf_pro_rst", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)] public static extern Int16 rf_pro_rst(IntPtr icdev, byte[] _Data); [DllImport("mwrf32.dll", EntryPoint = "rf_pro_trn", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)] public static extern Int16 rf_pro_trn(IntPtr icdev, byte[] problock, byte[] recv); [DllImport("mwrf32.dll", EntryPoint = "rf_ctl_mode", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)] public static extern Int16 rf_ctl_mode(IntPtr icdev, byte mode); //受控方式 [DllImport("mwrf32.dll")] public static extern Int16 rf_setbright(IntPtr icdev, byte bright); [DllImport("mwrf32.dll")] public static extern Int16 rf_disp_mode(IntPtr icdev, byte mode); [DllImport("mwrf32.dll")] public static extern Int16 rf_settime(IntPtr icdev, byte[] time); [DllImport("mwrf32.dll", EntryPoint = "rf_ctl_mode", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)] public static extern Int16 rf_settimehex(IntPtr icdev, string time); [DllImport("mwrf32.dll", EntryPoint = "rf_CtlBackLight", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)] public static extern Int16 rf_CtlBackLight(IntPtr icdev, byte cOpenFlag); //控制背光 [DllImport("mwrf32.dll", EntryPoint = "rf_LcdClrScrn", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)] public static extern Int16 rf_LcdClrScrn(IntPtr icdev, byte cLine); //清LCD屏 [DllImport("mwrf32.dll", EntryPoint = "rf_DispMainMenu", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)] public static extern Int16 rf_DispMainMenu(IntPtr icdev); //顯示歡迎光臨 [DllImport("mwrf32.dll", EntryPoint = "rf_DispLcd", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)] public static extern Int16 rf_DispLcd(IntPtr icdev, byte line, byte type); //顯示系統內置操作 [DllImport("mwrf32.dll", EntryPoint = "rf_DispInfo", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)] public static extern Int16 rf_DispInfo(IntPtr icdev, byte line, byte offset, byte[] data); //顯示信息,操作前需清屏 [DllImport("mwrf32.dll", EntryPoint = "rf_disp8", SetLastError = true, CharSet = CharSet.Auto, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)] public static extern Int16 rf_disp8(IntPtr icdev, Int16 disp_len, byte[] disp_str); //在讀寫器數碼管上顯示數字 public void bt1_Click() { icdev = usb_init(); //連接設備 if (icdev.ToInt32() > 0) { this.txt2.Text = "讀卡器連接成功!"; msg = "已連接到讀卡器............."; byte[] status = new byte[30]; var st3 = rf_get_status(icdev, status); //讀取硬件版本號 //lbHardVer.Text=System.Text.Encoding.ASCII.GetString(status); Console.WriteLine(System.Text.Encoding.Default.GetString(status)); rf_beep(icdev, 25); } else { this.txt2.Text = "未識別到到讀卡器,請檢查設備連接后重試!!!!!"; msg = "未識別到到讀卡器,請檢查設備連接后重試!!!!"; } } public static void bt2_Click() { byte[] key = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; byte mode = 0; //加載密碼,此密碼是用來驗證卡片的密碼 for (byte sector = 0; sector < 16; sector++) { var st1 = rf_load_key(icdev, mode, sector, key); if (st1 != 0) { string s1 = Convert.ToString(sector); // txt3.Text = s1 + " sector rf_load_key error!"; } } byte[] snr = new byte[5]; //卡片序列號 var st = rf_card(icdev, 0, snr); //尋卡 if (st != 0) { // txt3.Text = "未識別到IC卡!!!"; msg2 = "未識別到IC卡!!!"; } else { byte[] snr1 = new byte[8]; // txt3.Text = "識別到IC卡!!!!!" ; hex_a(snr, snr1, 4); //將卡號轉換為16進制字符串 msg2 = "識別到IC卡," + "IC卡號:" + System.Text.Encoding.Default.GetString(snr1); } } public static void bt3_Click() { var stcode = rf_authentication(icdev, 0, 2); //驗證密碼 if (stcode != 0) { // txt4.Text = "IC卡密碼錯誤!!!!!"; msg3 = "IC卡密碼錯誤!!!"; } else { // txt4.Text = "IC卡密碼正確!!!!!"; msg3 = "IC卡密碼正確!!!"; } } public static void bt4_Click() { byte[] databuffer = new byte[32]; byte block = 8; var st = rf_read_hex(icdev, block, databuffer); //讀數據,此函數讀出來的是16進制字符串,也就是把每個字節數據的16進制ASCⅡ碼以字符串形式輸出 if (st != 0) { // txt5.Text = "讀取IC卡數據失敗!" + st.ToString(); msg4 = "讀取IC卡數據失敗! " + st.ToString(); } else { // txt5.Text = "讀取IC卡數據成功!" + System.Text.Encoding.Default.GetString(databuffer); msg4 = "讀取IC卡數據成功!" + System.Text.Encoding.Default.GetString(databuffer); } } private void Button_Click(object sender, RoutedEventArgs e) { bt2_Click(); bt3_Click(); bt4_Click(); } }
參考:https://www.cnblogs.com/yijiayi/p/9867502.html