先尝试采用打开网络端口方法来连接设备
/// <summary> /// 连接指定设备 /// </summary> /// <returns>返回设备连接句柄</returns> public int OpenNetPort(string ipaddress, int port) { Entities.IOT.DeviceReader reader = new Entities.IOT.DeviceReader(); reader.Port = port; reader.IPAddress = ipaddress; int openresult = 0; try { openresult = StaticClassReaderB.OpenNetPort(reader.Port, reader.IPAddress, ref reader.ComAdr, ref reader.FrmHandle); } catch (Exception e) { openresult = -1; message = e.Message; } if (openresult == 0) { message = reader.IPAddress + ":" + reader.Port + "端口已经开启"; StaticClassReaderB.GetReaderInformation(ref reader.ComAdr, reader.VersionInfo, ref reader.ReaderType, reader.TrType, ref reader.dmaxfre, ref reader.dminfre, ref reader.PowerdBm, ref reader.ScanTime, reader.FrmHandle); Devices.TryAdd(reader.FrmHandle, reader); } if (openresult == 0x35 || openresult == 0x30) { StaticClassReaderB.CloseNetPort(reader.FrmHandle); message = "TCP/IP通讯错误"; } return reader.FrmHandle; }
终于遇到阻力了,返回值为48(0x30)通讯错误,首先核对传入的参数,经核对传参正确,通讯错误是因为之前RD900M-2000读头工作模式设置为“主动模式”(主动模式:设备扫描到RFID卡信息后自动将消息发送至服务器指定端口,应答模式:设备将扫描到RFID卡信息存入缓存,等待服务器发起轮询到此设备端口时在将消息回复给服务器),主动模式下设备将不再支持由服务器打开端口指令。
SDK说明文档中主动上报模式设置截图:
既然这样就变得简单了,先用网络调试助手查看,证实设备正常上报了数据:
下一步需要建立持续Socket连接,监视端口数据并解析,需要补习Socket知识了......
第一步,先写个控制台测试代码方便调试:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net; using System.Net.Sockets; namespace SocketTest { class Program { static void Main(string[] args) { try { int port = 8080;//指定监听端口 IPEndPoint ipe = new IPEndPoint(IPAddress.Any, port);//本机调试,可以不用设置IP地址 Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//创建一个Socket类 socket.Bind(ipe);//绑定端口 socket.Listen(0);//开始监听(测试时队列设置0也可以) Console.WriteLine("Wait for connect"); Socket serverSocket = socket.Accept();//为新建连接创建新的Socket。 Console.WriteLine("Get a connect"); byte[] buffer = new byte[4096]; int length = serverSocket.Receive(buffer, buffer.Length, 0);//从客户端接收信息 byte[] receiveByte = new byte[length];//设置有效数据字节数组 Array.Copy(buffer, receiveByte, length); string text = BitConverter.ToString(receiveByte, 0).Replace("-", " ");//byte字节转换为16进制文本 Console.WriteLine("Server Get Message:{0}", text);//把客户端传来的信息显示出来 serverSocket.Close(); socket.Close(); } catch (ArgumentNullException e) { Console.WriteLine("ArgumentNullException: {0}", e); } catch (SocketException e) { Console.WriteLine("SocketException: {0}", e); } Console.WriteLine("Press Enter to Exit"); Console.ReadLine(); } } }
可以收到读头上报的数据,11 00 6E是标志位,后续至第二个标志位前的数字既是RFID卡号
完成第二步,填写项目代码,建立一个通用型的Socket监听管理类,辅助类有2个:SocketClient(包括客户端Socket连接实例等相关属性), SocketReceiveData(包括Socket客户端发送的数据也就是服务端接收的数据的相关属性)
using System; using System.Collections.Generic; using System.Collections.Concurrent; using System.Linq; using System.Text; using System.Net; using System.Net.Sockets; namespace Mvcms.Common.Net { /// <summary> /// Socket端口监听管理类 /// </summary> public class SocketHelper { /// <summary> /// 监听队列上限 /// </summary> protected const int LISTEN_QUEUE_MAX = 20; /// <summary> /// 保存接收数据队列上限 /// </summary> protected const int RECEIVE_QUEUE_MAX = 1000; #region 静态成员变量 /// <summary> /// 接收数据事件代理 /// </summary> /// <param name="socketClient"></param> /// <param name="e"></param> public delegate void ReceiveDataEventHandler(SocketClient socketClient, SocketReceiveData e); /// <summary> /// 接收数据静态事件 /// </summary> public static event ReceiveDataEventHandler ReceiveDataEvent; /// <summary> /// 当前连接的Socket客户端 /// </summary> protected static List<SocketClient> socketClients = new List<SocketClient>(); /// <summary> /// 已开启的Socket端口监听对象 /// </summary> protected static ConcurrentDictionary<int, Socket> socketServers = new ConcurrentDictionary<int, Socket>(); /// <summary> /// 队列方式保存客户端上报的数据 /// </summary> protected static Queue<SocketReceiveData> queue_receiveData = new Queue<SocketReceiveData>(); /// <summary> /// 泛型列表保存客户端上报的数据 /// </summary> protected static List<SocketReceiveData> list_receiveData = new List<SocketReceiveData>(); /// <summary> /// 保存各端口接收数据次数 /// </summary> protected static ConcurrentDictionary<int, int> portReceiveCount = new ConcurrentDictionary<int, int>(); /// <summary> /// 保存异常消息 /// </summary> protected static string message = string.Empty; /// <summary> /// 保存异常消息,读取后自动清空 /// </summary> public static string Message { get { string result = message; message = string.Empty; return result; } } /// <summary> /// 活动的客户顿Socket连接 /// </summary> public List<SocketClient> GetSocketClients { get { return socketClients; } } /// <summary> /// 已开启的监听服务 /// </summary> public ConcurrentDictionary<int, Socket> GetSocketServers { get { return socketServers; } } /// <summary> /// 从队列获取接收到的最早一条的客户端数据 /// </summary> public SocketReceiveData PeekReceiveData() { return queue_receiveData.Peek(); } /// <summary> /// 获取端口最新接收的数据 /// </summary> /// <param name="port"></param> /// <returns></returns> public SocketReceiveData GetLastReceiveData(int port) { return list_receiveData.FindLast(p => p.LocalPort == port); } public SocketReceiveData GetLastReceiveData(string ipaddress, int port) { return list_receiveData.FindLast(p => p.RemoteIP == ipaddress && p.LocalPort == port); } /// <summary> /// 获取指定端口接收数据次数 /// </summary> /// <param name="port"></param> /// <returns></returns> public int GetPortReceiveCount(int port){ int count = 0; if (port == 0) { foreach (KeyValuePair<int, int> kv in portReceiveCount) { count += kv.Value; } } else { portReceiveCount.TryGetValue(port, out count); } return count; } /// <summary> /// 获取接收数据总次数 /// </summary> public int GetReceiveCount { get { return portReceiveCount.Count; } } #endregion /// <summary> /// 是否存在监听端口 /// </summary> public bool IsListen { get { return socketServers.Count > 0; } } /// <summary> /// 获取异常消息 /// </summary> /// <returns></returns> public string GetMessage() { return Message; } /// <summary> /// 开启端口监听 /// </summary> /// <param name="port"></param> /// <returns></returns> public bool OpenListenNetPort(int port) { ///获取本地的IP地址,代码不够完善,服务器可能存在多个IP地址 //string ipAddress = "127.0.0.1"; //IPAddress[] addressList = Dns.GetHostEntry(Dns.GetHostName()).AddressList; //foreach (IPAddress _IPAddress in addressList) { // if (_IPAddress.AddressFamily.ToString() == "InterNetwork") { // ipAddress = _IPAddress.ToString(); // break; // } //} //判断端口是否已经开启了监听服务 if(socketServers.ContainsKey(port)){ message = "端口 "+ port +" 已经处于监听状态!"; return false; } bool result = true; //建立Socket监听实例 //IPAddress ip = IPAddress.Parse(ipAddress); try { Socket socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); socketServer.Bind(new IPEndPoint(IPAddress.Any, port));//绑定端口 socketServer.Listen(LISTEN_QUEUE_MAX);//监听队列上限 socketServer.BeginAccept(new AsyncCallback(Accept), socketServer);//开始接受连接 socketServers.TryAdd(port, socketServer);//添加监听实例到静态列表 } catch (Exception e) { message = e.Message; result = false; } return result; } /// <summary> /// 关闭端口监听 /// </summary> /// <returns></returns> public bool CloseListenNetPort(int port) { //尝试获取端口监听实例 Socket socket; if(!socketServers.TryGetValue(port, out socket)){ message = "端口 "+ port +" 未开启监听服务,操作中止!"; return false; } bool result = true; try { //关闭监听服务 socket.Close(); //从监听服务列表移除实例 result = socketServers.TryRemove(port, out socket); if (!result) { message = "移除Socket对象失败!"; } } catch (Exception e) { message = e.Message; result = false; } return result; } /// <summary> /// 处理客户端连接请求 /// </summary> /// <param name="sender"></param> protected void Accept(IAsyncResult sender) { //判断是否存在监听实例 if (!IsListen) { return; } try { //还原传入的原始套接字 Socket socketServer = (Socket)sender.AsyncState; //在原始套接字上调用EndAccept方法,返回新的套接字 SocketClient socketClient = new Net.SocketClient(socketServer.EndAccept(sender)); //添加客户端Socket实例到客户端实例列表中,接收数据要用到 socketClients.Add(socketClient); //接收客户端数据 socketClient.BeginReceive(new AsyncCallback(Receive)); //准备接收下一个客户端 socketServer.BeginAccept(new AsyncCallback(Accept), socketServer); } catch (Exception e) { message = e.Message; } } /// <summary> /// 开始接收客户端上报的数据 /// </summary> /// <param name="sender"></param> protected void Receive(IAsyncResult sender) { //转换获取客户端Socket连接实例 Socket socketClient = (Socket)sender.AsyncState; string[] remoteendport = socketClient.RemoteEndPoint.ToString().Split(':'); string remote_ip = remoteendport[0];//获取远程IP地址 //在客户端连接实例列表查询当前客户端,此客户端已在Accept方法中保存 SocketClient client = socketClients.Find(p => p.IpAddress == remote_ip); byte[] receiveBytes = null; if (client == null) { return; } //用线程安全的数据字典保存监听端口接收数据计次 int portCount; if (portReceiveCount.TryGetValue(client.ServerPort, out portCount)) { //已存在端口计数值,计数器+1 int newValue = portCount + 1; portReceiveCount.TryUpdate(client.ServerPort, newValue, portCount); } else { //端口第一次获取数据,计数器为1 portReceiveCount.TryAdd(client.ServerPort, 1); } try { //开始接收数据 receiveBytes = client.GetReceiveData(sender); } catch (Exception e) { message = e.Message; socketClient.Disconnect(true); } if (receiveBytes != null) { //成功接收到数据,保存数据到接收数据静态列表中 SocketReceiveData receiveData = new SocketReceiveData(); receiveData.LocalIP = client.ServrIpAddress; receiveData.LocalPort = client.ServerPort; receiveData.ReceiveBytes = receiveBytes; receiveData.ReceiveTime = DateTime.Now; receiveData.RemoteIP = client.IpAddress; receiveData.RemotePort = client.Port; //调用接收数据虚方法,继承类可复写此方法实现定制数据逻辑 SocketReceiveData(client, receiveData); //触发接收到客户端上报数据静态事件 if (ReceiveDataEvent != null) { ReceiveDataEvent(client, receiveData); } } client.Close();//关闭当前客户端Socket连接 socketClients.Remove(client);//从客户端连接实例列表移除当前连接实例 } public virtual void SocketReceiveData(SocketClient socketClient, SocketReceiveData receiveData){ //保存到队列集合 if (queue_receiveData.Count > RECEIVE_QUEUE_MAX) { queue_receiveData.Peek();//达到保存数据队列上限,抛弃最早的数据 } queue_receiveData.Enqueue(receiveData); //保存到泛型列表 if (list_receiveData.Count > RECEIVE_QUEUE_MAX) { list_receiveData.RemoveAt(list_receiveData.Count - 1);//达到保存数据队列上限,抛弃最早的数据 } list_receiveData.Add(receiveData); } } /// <summary> /// 连接的客户端 /// </summary> public partial class SocketClient { /// <summary> /// 连接的客户端 /// </summary> private Socket clientSocket; /// <summary> /// 接收数据缓冲区 /// </summary> private byte[] buffer; /// <summary> /// 客户端IP地址和端口号对象 /// </summary> private EndPoint endPoint; /// <summary> /// 客户端IP地址 /// </summary> private string ipaddress; /// <summary> /// 客户端端口号 /// </summary> private int port; /// <summary> /// 服务端IP地址 /// </summary> private string server_ip; /// <summary> /// 服务端监听端口号 /// </summary> private int server_port; /// <summary> /// 客户端类型 /// </summary> private int clientType; /// <summary> /// 最后一次连接时间,可用于判断是否超时 /// </summary> private DateTime lastTime; /// <summary> /// 客户端Socket连接状态类构造函数 /// </summary> /// <param name="socket">客户端Socket</param> public SocketClient(Socket socket) { clientSocket = socket;//当前客户端连接实例 string[] cs = socket.RemoteEndPoint.ToString().Split(':'); ipaddress = cs[0];//客户端IP地址 port = int.Parse(cs[1]);//客户端端口号,无实际用处 lastTime = DateTime.Now; buffer = new byte[1024]; string[] ss = socket.LocalEndPoint.ToString().Split(':'); server_ip = ss[0];//服务端IP地址 server_port = int.Parse(ss[1]);//服务端接收数据端口号 } /// <summary> /// 开始接收客户端发送的数据 /// </summary> /// <param name="receive"></param> public void BeginReceive(AsyncCallback receive) { //开始接收数据 clientSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, receive, clientSocket); } /// <summary> /// 获取客户端发送来的数据 /// </summary> /// <param name="asyncResult"></param> /// <returns></returns> public byte[] GetReceiveData(IAsyncResult asyncResult) { int length = 0; length = clientSocket.EndReceive(asyncResult);//接收客户端发送数据,获取数据长度 byte[] result = new byte[length]; Array.Copy(buffer, result, length);//从数据缓冲区复制有效数据 return result; } /// <summary> /// 关闭当前客户端连接实例 /// </summary> public void Close() { clientSocket.Close(); } /// <summary> /// 连接的客户端 /// </summary> public Socket Client { get { return clientSocket; } } /// <summary> /// 客户端IP地址 /// </summary> public string IpAddress { get { return ipaddress; } } /// <summary> /// 客户端发送端口 /// </summary> public int Port { get { return port; } } /// <summary> /// 客户端最新一次建立连接时间 /// </summary> public DateTime LastTime { get { return lastTime; } } /// <summary> /// 服务端IP地址 /// </summary> public string ServrIpAddress { get { return server_ip; } } /// <summary> /// 服务端端口号 /// </summary> public int ServerPort { get { return server_port; } } } /// <summary> /// 接收上报数据实体类 /// </summary> public partial class SocketReceiveData { /// <summary> /// 接收上报数据时间 /// </summary> public DateTime ReceiveTime { get; set; } /// <summary> /// 上报数据主机IP /// </summary> public string RemoteIP { get; set; } /// <summary> /// 上报数据主机端口号 /// </summary> public int RemotePort { get; set; } /// <summary> /// 本地主机IP /// </summary> public string LocalIP { get; set; } /// <summary> /// 本地主机接收数据端口号 /// </summary> public int LocalPort { get; set; } /// <summary> /// 接收到的数据 /// </summary> public byte[] ReceiveBytes { get; set; } } }
端口监听数据实体,与数据库字段完全对应
using System; using System.ComponentModel.DataAnnotations; namespace Mvcms.Entities.IOT { public class listen_port { /// <summary> /// 自增字段 /// </summary> public int id { get; set; } /// <summary> /// 监听IP地址 /// </summary> [Display(Name="监听IP地址", Description="单网卡可以不填")] public string ipaddress { get; set; } /// <summary> /// 监听端口 /// </summary> [Range(6000,65535, ErrorMessage="请填写6000-65535范围端口号")] [Display(Name="监听端口", Description="填写6000-65535端口号")] public int port { get; set; } /// <summary> /// 绑定的卡类型(card_type.id数组) /// </summary> [Display(Name="绑定卡类型", Description="未选中的卡类型,上报的数据将被忽略")] public string bind_card_type { get; set; } /// <summary> /// 监听端口标题名称 /// </summary> [Display(Name="标题名称", Description="监听端口功能名称标题")] public string title { get; set; } /// <summary> /// 监听端口功能描述 /// </summary> [Display(Name="功能描述", Description="端口功能详细描述")] public string description { get; set; } } }
端口监听数据模型,每个监听端口可以绑定多种RFID类型卡
using System; using System.Collections.Generic; using System.Reflection; namespace Mvcms.Models.IOT { /// <summary> /// 监听端口数据模型 /// </summary> public class listen_port : Entities.IOT.listen_port { public listen_port() : base() { } public listen_port(Entities.IOT.listen_port entity) : base() { PropertyInfo[] props = entity.GetType().GetProperties(); foreach (PropertyInfo pi in props) { pi.SetValue(this, pi.GetValue(entity)); } } /// <summary> /// 端口绑定卡类型 /// </summary> public int[] array_bind_card_type { get { List<int> result = new List<int>(); if (!string.IsNullOrEmpty(bind_card_type)) { string[] ss = bind_card_type.Split(','); for (int i = 0; i < ss.Length; i++) { int id; if (int.TryParse(ss[i], out id)) { result.Add(id); } } } return result.ToArray(); } set { string text = string.Empty; if (value.Length > 0) { text = string.Join(",", value); } bind_card_type = text; } } /// <summary> /// 获取或设置端口绑定的卡类型 /// </summary> public List<Entities.IOT.card_type> list_card_type { get; set; } /// <summary> /// 是否为监听状态 /// </summary> public bool IsListen { get; set; } } }
端口监听控制器代码
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Web.Mvc; using System.Net; using System.Net.Sockets; using Mvcms.Common; using Mvcms.Common.Net; namespace Mvcms.Web.Controllers.admin.IOT { public class listen_port_listController: UI.Controllers.BaseManageController { private static ReaderDeviceHelper readerDeviceHelper = new ReaderDeviceHelper(); /// <summary> /// 获取监听端口列表 /// </summary> /// <returns></returns> public ActionResult Index() { List<Models.IOT.listen_port> list = new BLL.IOT.listen_port().GetModelList(); IsPlugin = true; foreach (Models.IOT.listen_port item in list) { item.IsListen = readerDeviceHelper.GetSocketServers.ContainsKey(item.port); } return View(GetViewName("/IOT/listen_port_list.cshtml"), list); } /// <summary> /// 提交采用Socket开启监听指定端口 /// </summary> /// <returns></returns> [HttpPost] public ActionResult SubmitOnListen() { string jsondata = request.Form["jsondata"].ToString();//获取ajax发送的Form参数 if (!request.Success) { return JsDialog(request.HtmlMessage(), false); } Dictionary<int, int> dict = JsonHelper.JSONToObject<Dictionary<int, int>>(jsondata); //key: id, Value: 0:未选中,1:已选中 if (dict == null) { return JsDialog("Json数据格式错误!", false); } if (dict.Count == 0) { return JsDialog("没有可操作端口!", false); } List<string> mess = new List<string>(); int success = 0; int select_count = 0; foreach (KeyValuePair<int, int> kv in dict) { if (kv.Value == 1) { select_count++; int port = kv.Key; bool result = readerDeviceHelper.OpenListenNetPort(port); if (result) { success++; } else { mess.Add("开启 " + port + " 端口监听失败:" + readerDeviceHelper.GetMessage()); } } } if (select_count == 0) { return JscriptMsg("请选择要操作的数据!", false); } if (success == dict.Count) { return JsDialog("已成功开启 " + success + " 个端口监听服务", true); } else { return JsDialog("有 "+ (select_count - success) +" 个端口开启监听失败:" + string.Join("<br/>", mess), false); } } /// <summary> /// 提交关闭指定端口监听服务 /// </summary> /// <returns></returns> [HttpPost] public ActionResult SubmitOffListen() { string jsondata = request.Form["jsondata"].ToString();//获取ajax发送的Form参数 if (!request.Success) { return JsDialog(request.HtmlMessage(), false); } Dictionary<int, int> dict = JsonHelper.JSONToObject<Dictionary<int, int>>(jsondata); //key: id, Value: 0:未选中,1:已选中 if (dict == null) { return JsDialog("Json数据格式错误!", false); } if (dict.Count == 0) { return JsDialog("没有可操作端口!", false); } List<string> mess = new List<string>(); int success = 0; int select_count = 0; foreach (KeyValuePair<int, int> kv in dict) { if (kv.Value == 1) { select_count++; int port = kv.Key; bool result = readerDeviceHelper.CloseListenNetPort(port); if (result) { success++; } else { mess.Add("关闭 " + port + " 端口监听失败:" + readerDeviceHelper.GetMessage()); } } } if (select_count == 0) { return JscriptMsg("请选择要操作的数据!", false); } if (success == dict.Count) { return JsDialog("已成功关闭 " + success + " 个端口监听服务", true); } else { return JsDialog("有 " + (select_count - success) + " 个端口关闭监听失败:" + string.Join("<br/>", mess), false); } } /// <summary> /// 获取指定端口接收到的最新数据,并包含简单统计信息 /// </summary> /// <returns></returns> public ActionResult GetReceiveData() { int port = request.QueryString["port"].ToInt(); if (!readerDeviceHelper.GetSocketServers.ContainsKey(port)) { return JsonText("端口 " + port + " 未开启监听!", false); } string text = SocketHelper.Message; text += "端口:" + port + ", 数据条数:" + readerDeviceHelper.GetPortReceiveCount(port) + "<br/>"; SocketReceiveData finditem = readerDeviceHelper.GetLastReceiveData(port); if (finditem != null) { text += "最后接收<br/>时间:" + finditem.ReceiveTime.ToString() + ", 远程主机:" + finditem.RemoteIP + ", 数据:<br/>"; text += BitConverter.ToString(finditem.ReceiveBytes, 0).Replace("-", " ").Replace("11 00 6E", "<br/>11 00 6E");//byte字节转换为16进制文本 return JsonText(text, true); } else { return JsonText("没有数据!", true); } } /// <summary> /// 获取最新接收的读头上报卡号 /// </summary> /// <returns></returns> public ActionResult GetLastCardNo() { int seconds_diff = request.QueryString["seconds_diff"].ToInt(30); DateTime date = DateTime.Now.AddSeconds(-seconds_diff); ReaderReceiveData finditem = readerDeviceHelper.GetLastReceiveData(date); if (!readerDeviceHelper.IsListen) { return JsonText("端口未开启监听,请联系管理员!", false); } if (finditem != null) { string data = JsonHelper.ObjectToJSON(finditem.EPC); string json = "{\"status\":1, \"msg\":\""+ finditem.ReceiveTime.ToString() +"\", \"ip\":\""+ finditem.RemoteIP +"\", \"data\":" + data + "}"; return Content(json); } else { return JsonText("未读到上报RFID卡号数据,请重新刷卡在试!", false); } } } }
监听端口管理视图页面截图
开启监听后将RFID卡放置于RD915M-2000读头前面,读头将自动读取标签并上报数据至服务器10.100.100.254(开发电脑)指定端口,点击获取“查看接收数据”将调用控制器GetReceiveData动作获取接收的数据
显示读到2条RFID卡信息,每条数据包涵了多条重复卡号是因为开启了群读(没有延迟),接收上报数据至此已经完成,后续将是数据库操作(解析卡号,保存读卡记录)。
共有条评论 网友评论