背景: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
