/// <summary> /// 绑定数据 /// </summary> private void BindData() { List <ClientInfo> list = new List <ClientInfo>(); //这句代码会出现在枚举出错,在枚举的过程中,列表元素被改变了 //list = DTU_ClientManager.Clients.Select(c => //{ // return new ClientInfo // { // Tel = c.Tel, // Name = c.Name, // RegisterTime = c.RegisterTime, // LastVisitTime = c.LastVisitTime // }; //}).ToList(); int length = DTU_ClientManager.Clients.Count; for (int i = 0; i < length; i++) { try { DTUClientInfo item = DTU_ClientManager.Clients[i]; list.Add(new ClientInfo() { StationId = item.StationId, Tel = item.TelOrGprsId, Name = item.Name, RegisterTime = item.RegisterTime, LastVisitTime = item.LastVisitTime }); } catch (Exception) { } } list.AddRange(ServerSocketHelper.ClientSockets); dataGridView1.DataSource = list; }
/// <summary> /// 更新客户端的最后一次访问时间 /// </summary> /// <param name="clientInfo"></param> /// <param name="datetime"></param> public static void UpdateLastVisitTime(DTUClientInfo clientInfo, DateTime datetime) { clientInfo.LastVisitTime = datetime; if (ClientChangeHander != null) { ClientChangeHander(); } }
private static void Execute(object state) { //锁住客户端连接,接收客户端的心跳数据, //如果没有心跳数据则跳过, //如果有心跳数据,则将客户端更新到客户端列表。 DTUClientInfo client = (DTUClientInfo)state; DTU_ClientManager.UpdateLastVisitTime(client, DateTime.Now); using (MyLock mylock = new MyLock(client, 3000, false)) { if (mylock.IsTimeout == false) //判断锁是否成功,如果没有超时,则表示锁成功 { try { byte[] content = new byte[GlobalPara.CONTENT_LENGTH]; int conLen = 0; byte type = 0; string tel = ""; string protocol = ""; Util.DTU.rdata(ref protocol, client.socket, GlobalPara.ReceiveTimeOut, ref content, ref conLen, ref type, ref tel); //1秒超时 Util.DTU.HandlerData(protocol, client.socket, content, conLen, type, tel); byte[] pack = new byte[1024 * 2]; client.socket.ReceiveTimeout = 50; int packLen = client.socket.Receive(pack, SocketFlags.None); if (MsgHandler != null) { MsgHandler("收到的心跳:" + CommonUtil.byteToHexStr(pack, packLen)); } ////判断收到的数据是不是心跳 如果是心跳数据,则解析出gprsId,并更新客户端列表 //int gprsId = 0; //bool flag = GPRS_Protocol.UnPack_Heartbeat(pack, packLen, ref gprsId); //if (flag) //{ // ClientManager.AddClient(client.socket, gprsId.ToString()); // //pack[1] = Protocol.Type_Heartbeat_StoC; // //这里重新组个返回心跳包。 // BackHeartBeat(client.socket, gprsId); //} } catch (Exception) { } } } }
private static void 添加DTU控制任务(SWSDataContext db) { try { //查询出一个小时内有指令的站点的id //List<int> stations = db.ExecuteQuery<int>("SELECT station_id FROM dbo.control_command where (state=0 OR state IS NULL) and communication_mode=2 and datediff(mi,add_datetime,GETDATE())<60 group by station_id ").ToList(); List <int> stations = db.ExecuteQuery <int>("SELECT station_id FROM dbo.control_command where (state=0 OR state IS NULL) and (communication_mode=2 or tp='3') group by station_id ").ToList(); if (stations.Count == 0) { return; } ///站点id和transfer_code的键值对 List <Station_transferCode> StaTrans = db.ExecuteQuery <Station_transferCode>("SELECT id as stationId,transfer_code FROM dbo.country_station WHERE transfer_code IS NOT NULL AND transfer_code<>'' AND transfer_code<>'null'").ToList(); //循环站点 将站点添加到线程池 foreach (int stationid in stations) { try { Station_transferCode StaTran = StaTrans.SingleOrDefault(c => c.stationId == stationid); //如果这个站点没有配置dtu 就跳过 if (StaTran == null) { continue; } //根据设备唯一编号 找出 DTUClientInfo DTUClientInfo client = DTU_ClientManager.Clients.SingleOrDefault(c => c.TelOrGprsId == StaTran.transfer_code); if (client == null) { continue; } //如果客户端在【任务队列】和【线程里】里已经存在了,就不继续添加 if (!HasExistClientInPool(client)) { PoolA.AddTaskItem(new WaitCallback(ExecuteDtuOrder), client); } } catch (Exception ex) { LogMg.AddError(ex); } } } catch (Exception ex) { LogMg.AddError(ex); } }
/// <summary> /// 根据socket 查找这个站点所使用的DTU采用的传输协议 /// </summary> /// <param name="socket"></param> /// <returns></returns> public static string GetProtocolBySocket(Socket socket) { string protocol = ""; try { DTUClientInfo client = Clients.SingleOrDefault(c => c.socket == socket); if (client != null) { protocol = client.Protocol; } } catch (Exception ex) { LogMg.AddError(ex); } return(protocol); }
/// <summary> /// 判断客户端在【任务队列】和【线程里】里是否已经存在 /// </summary> /// <param name="client"></param> /// <returns></returns> private static bool HasExistClientInPool(DTUClientInfo client) { try { foreach (TaskPool.Waititem item in PoolC.waitlist) { DTUClientInfo content = (DTUClientInfo)item.Context; if (content.GetHashCode() == client.GetHashCode()) { return(true); } } //if (PoolC.publicpool.Count > 1) //{ foreach (KeyValuePair <string, Task> item in PoolC.publicpool) { try { Task task = (Task)item.Value; DTUClientInfo content = (DTUClientInfo)task.contextdata; if (content.GetHashCode() == client.GetHashCode()) { return(true); } } catch (Exception) { } } //} } catch (Exception) { } return(false); }
/// <summary> /// 执行DTU控制任务 /// </summary> /// <param name="state"></param> private static void ExecuteDtuOrder(object state) { //1.锁住客户端对象 //2.找出客户端对应的数据库,并找出需要执行的控制指令。 //3.循环发送指令到客户端,再接收返回的数据,存入数据库。 //4.释放客户端对象 DTUClientInfo client = (DTUClientInfo)state; using (MyLock mylock = new MyLock(client, 20000, false)) { if (mylock.IsTimeout == false) { //LogManager.AddDebug("ControlCommandThread线程:" + Thread.CurrentThread.ManagedThreadId + " 开始锁了 是否超时" + mylock.IsTimeout); //找出这个站点对应的数据库, 并获取数据库连接 SqlConnection connection = GetDbConnectionByTel(client.TelOrGprsId); if (connection == null) //找不到对应的数据库连接 { LogMg.AddDebug(string.Format("根据Tel={0}的设备唯一id,在sysconfig.xml中找不到对应的数据库连接", client.TelOrGprsId.ToString())); return; } SWSDataContext db = new SWSDataContext(connection); takePhoto(db, client.StationId, client); //把那些不需要执行了的数据 state=1 就当这行指令已经执行过了 List <int> giveUpCommands = db.ExecuteQuery <int>("SELECT id FROM dbo.control_command WHERE station_id=" + client.StationId + " AND (state=0 OR state IS NULL) AND id NOT IN (SELECT MAX(id) FROM dbo.control_command WHERE station_id=" + client.StationId + " AND (state=0 OR state IS NULL) GROUP BY gong_kuang_id,read_or_write) ").ToList(); if (giveUpCommands.Count > 0) { db.ExecuteCommand("UPDATE dbo.control_command SET state=1 WHERE id in(" + string.Join(", ", giveUpCommands) + ")"); } //db.ExecuteCommand("UPDATE dbo.control_command SET state=1 WHERE station_id=" + client.StationId + " AND (state=0 OR state IS NULL) AND id NOT IN (SELECT MAX(id) FROM dbo.control_command WHERE station_id=" + client.StationId + " AND (state=0 OR state IS NULL) GROUP BY gong_kuang_id,read_or_write) "); //获取需要执行的指令 List <control_command> commands = db.ExecuteQuery <control_command>("SELECT * FROM dbo.control_command WHERE id IN(SELECT MAX(id) FROM dbo.control_command WHERE station_id=" + client.StationId + " AND communication_mode=2 AND (state=0 OR state IS NULL) GROUP BY gong_kuang_id,read_or_write) ORDER BY add_datetime").ToList(); List <gong_kuang_config> gongKuangs = db.gong_kuang_config.Where(c => c.station_id == client.StationId).ToList(); foreach (control_command command in commands) //循环发送指令 { if (command.COUNT == null) { command.COUNT = 0; } try { gong_kuang_config gongkuang = gongKuangs.SingleOrDefault(c => c.id == command.gong_kuang_id); if (gongkuang == null) //如果找不到command对应和gongkuangid,则把这条command标记为执行失败。 { LogMg.AddError("找不到控制命令所对应的工况配置信息"); command.execute_result = 0; //标记为执行失败 command.state = 1; // 就当已经执行过 command.execute_comment = "执行失败,找不到控制命令所对应的工况配置信息"; command.complete_datetime = DateTime.Now; db.SubmitChanges(); continue; } byte address = (byte)gongkuang.address; ClearSocketCache(client.socket);//清除缓冲区 LogMg.AddDebug("hashcode=" + client.socket.GetHashCode()); ModbusReturn modbusReturn = new ModbusReturn(); if (command.read_or_write == 0) //读读读读读读读读读读读 { while (modbusReturn.success == false && command.COUNT < SysConfig.userProfile.ExecuteFailureCount) { modbusReturn.clear(); modbus.readdata(client.Protocol, client.socket, "", address, ushort.Parse(gongkuang.read_register), int.Parse(gongkuang.function_code), gongkuang.data_type, gongkuang.decode_order, (int)gongkuang.receive_timeout, modbusReturn); //LogManager.AddDebug(String.Format("执行读命令 GPRSID:{0} gongkuangid:{1} address{2} 读寄存器编号:{3} 读取的值{4} 方法的返回bool值:{5}", client.TelOrGprsId, gongkuang.id, address, gongkuang.read_register, value.ToString(), flag)); command.COUNT++; } command.state = 1; //标志为已发送 if (modbusReturn.success == true) { DTU_ClientManager.UpdateLastVisitTime(client, DateTime.Now); command.execute_result = 1; //标记为执行成功 command.value = Convert.ToString(modbusReturn.value); gongkuang.read_value = Convert.ToString(modbusReturn.value); gongkuang.execute_comment = "执行读取操作成功"; if (gongkuang.config_type == "05") { try { test test = db.test.Single(c => c.testid == gongkuang.testid); test.value = Convert.ToString(modbusReturn.value * gongkuang.Multiple + gongkuang.AddNumber); } catch (Exception ex) { LogMg.AddError(ex); LogMg.AddDebug("找不到工况对应的检测点,gongkuangid=" + gongkuang.id + " testid=" + gongkuang.testid); } } } else { command.execute_result = 0; //标记为执行失败 gongkuang.execute_comment = "执行读取操作失败"; } command.execute_comment = modbusReturn.ToString(); } else //写写写写写写写写写写写写写写写 { while (modbusReturn.success == false && command.COUNT < SysConfig.userProfile.ExecuteFailureCount) { modbusReturn.clear(); modbus.writedata(client.Protocol, client.socket, "", address, ushort.Parse(gongkuang.write_register), gongkuang.data_type, (int)gongkuang.receive_timeout, short.Parse(command.value), modbusReturn); //LogManager.AddDebug(String.Format("执行写命令 GPRSID:{0} address{1} 写寄存器编号:{2} 写入的值{3} 方法的返回bool值:{4}", client.TelOrGprsId, address, gongkuang.write_register, command.value, flag)); command.COUNT++; } command.state = 1; //标志为已发送 if (modbusReturn.success == true) { DTU_ClientManager.UpdateLastVisitTime(client, DateTime.Now); command.execute_result = 1; //标记为执行成功 gongkuang.write_value = command.value; gongkuang.execute_comment = "执行写操作成功"; } else { command.execute_result = 0; //标记为执行失败 gongkuang.execute_comment = "执行写操作失败"; } command.execute_comment = modbusReturn.ToString(); } gongkuang.execute_datetime = DateTime.Now; command.complete_datetime = DateTime.Now; } catch (Exception ex) { command.execute_result = 0; //标记为执行失败 command.execute_comment = "执行命令失败,服务程序出现了异常"; // MessageQueue.Enqueue_DataInfo(string.Format("接收时间:【{0}】,站点:{1}, 执行工况配置失败.程序出现异常,请查看日志. ", DateTime.Now, station.name)); LogMg.AddError(ex); } finally { command.complete_datetime = DateTime.Now; } db.SubmitChanges(); } //LogManager.AddDebug("ControlCommandThread线程:" + Thread.CurrentThread.ManagedThreadId + " 释放锁了 "); } else { LogMg.AddDebug("ControlCommandThread 锁失败了"); } } }
private static void ExecuteOrder(object state) { ///第一步:找出需要采集的指标 ///第二步:循环采集的指标,取出一个指标, ///第三步:锁住客户端 ///第四步:采集 ///第五步:释放客户端 ///第六步:回到第二步 ///结束 DTUClientInfo client = (DTUClientInfo)state; Clazz.Config.XML_Station station = SysConfig.DTU_StationConfig.GetStationByTel(client.TelOrGprsId); if (station == null) { return; } List <Clazz.Config.XML_Test> listTest = station.ListTest; if (station != null && listTest != null) { foreach (Clazz.Config.XML_Test test in listTest) { using (MyLock mylock = new MyLock(client, 3000, false)) // 在循环内锁 { if (mylock.IsTimeout == false) { //LogManager.AddDebug("AutoCollectionThread 线程:" + Thread.CurrentThread.ManagedThreadId + " 开始锁了 是否超时" + mylock.IsTimeout); try { ModbusReturn modbusReturn = new ModbusReturn(); int count = 0; //执行错误的次数 while (modbusReturn.success == false && count < SysConfig.userProfile.ExecuteFailureCount) { modbusReturn.clear(); LogMg.AddDebug(string.Format("开始接收 时间:{0},站点:{1} tel:{2},testid:{3}", DateTime.Now.ToString(), client.Name, client.TelOrGprsId.ToString(), test.TestId)); modbus.readdata(client.Protocol, client.socket, client.TelOrGprsId, test.Address, test.RegisterNo, test.FunctionCode, test.DataType, test.DecodeOrder, test.ReceiveTimeout, modbusReturn); count++; } if (modbusReturn.success) //接收数据成功 { DTU_ClientManager.UpdateLastVisitTime(client, DateTime.Now); if (Between(modbusReturn.value * test.Multiple + test.AddNumber, test.Min, test.Max)) //如果值不在取值范围内,则不要 { SWSDataContext db = new SWSDataContext(Util.ServerSocketHelper.GetConnection(station.Org.DBName)); SaveToDatabase(db, test.TestId, modbusReturn.value * test.Multiple + test.AddNumber); //保存数据 LogMg.AddDebug(string.Format("接收时间:{0}, tel:{1},value:{2},testid:{3}", DateTime.Now.ToString(), client.TelOrGprsId.ToString(), modbusReturn.value * test.Multiple + test.AddNumber, test.TestId)); // MessageQueue.Enqueue_DataInfo(string.Format("接收时间:【{0}】,站点:{1},testid:{2},值:{3}", DateTime.Now.ToString(), station.Name, test.TestId, value * test.Multiple + test.AddNumber)); } else { LogMg.AddDebug(string.Format("接收时间:【{0}】,站点:{1},testid:{2},乘以倍率之后的值:{3} 由于值不在范围内[{4},{5}],丢弃", DateTime.Now.ToString(), station.Name, test.TestId, modbusReturn.value * test.Multiple + test.AddNumber, test.Min, test.Max)); } } else { //接收数据失败 LogMg.AddDebug(string.Format("接收数据失败")); // MessageQueue.Enqueue_DataInfo(string.Format("接收时间:【{0}】,站点:{1},testid:{2}, 接收数据失败", DateTime.Now.ToString(), station.Name, test.TestId)); if (modbusReturn.ErrorMsg.Contains("设备未在线")) { return; } } } catch (SocketException) { } catch (Exception ex) { LogMg.AddError(ex); DEBUG.MsgBox(ex.ToString()); } //LogManager.AddDebug("AutoCollectionThread 线程:" + Thread.CurrentThread.ManagedThreadId + " 释放锁了 "); } else { LogMg.AddDebug("AutoCollectionThread 锁失败了"); } } } } }
/// <summary> /// 保存客户端的连接信息到数据库 /// </summary> private void SaveOnlineInfo() { while (true) { try { foreach (XML_Org org in SysConfig.orgConfig.Orgs) { try { SWSDataContext db = new SWSDataContext(Util.ServerSocketHelper.GetConnection(org.DBName)); //采用有屏版电控柜的客户端遍历 List <Clazz.Config.ClientConfig.XML_Station> list_station = SysConfig.clientConfig.AllStation.Where(c => c.OrgId == org.OrgId).ToList(); for (int i = 0; i < list_station.Count; i++) { ClientInfo client_info = ServerSocketHelper.ClientSockets.SingleOrDefault(c => c.TransferCode == list_station[i].TransferCode); if (client_info != null) { station_online_info online_info = db.station_online_info.SingleOrDefault(c => c.transfer_code == list_station[i].TransferCode); if (online_info != null) { online_info.name = client_info.Name; online_info.register_time = client_info.RegisterTime; online_info.last_visit_time = client_info.LastVisitTime; online_info.stationid = client_info.StationId; } else { online_info = new station_online_info(); online_info.transfer_code = client_info.TransferCode; online_info.name = client_info.Name; online_info.register_time = client_info.RegisterTime; online_info.last_visit_time = client_info.LastVisitTime; online_info.stationid = client_info.StationId; db.station_online_info.InsertOnSubmit(online_info); } List <station_online_info> deletes = db.station_online_info.Where(c => c.stationid == online_info.stationid && c.id != online_info.id).ToList(); if (deletes.Count > 0) { db.station_online_info.DeleteAllOnSubmit(deletes); } } } //采用DTU电控柜的客户端遍历 List <XML_Station> list_DTU_Station = SysConfig.DTU_StationConfig.Stations.Where(c => c.OrgId == org.OrgId).ToList(); for (int i = 0; i < list_DTU_Station.Count; i++) { DTUClientInfo DTU_clientinfo = DTU_ClientManager.Clients.SingleOrDefault(c => c.TelOrGprsId == list_DTU_Station[i].Tel); if (DTU_clientinfo != null) { station_online_info online_info = db.station_online_info.SingleOrDefault(c => c.dtu_tel == DTU_clientinfo.TelOrGprsId); if (online_info != null) { online_info.stationid = DTU_clientinfo.StationId; online_info.name = DTU_clientinfo.Name; online_info.register_time = DTU_clientinfo.RegisterTime; online_info.last_visit_time = DTU_clientinfo.LastVisitTime; } else { online_info = new station_online_info(); online_info.stationid = DTU_clientinfo.StationId; online_info.name = DTU_clientinfo.Name; online_info.register_time = DTU_clientinfo.RegisterTime; online_info.last_visit_time = DTU_clientinfo.LastVisitTime; online_info.dtu_tel = DTU_clientinfo.TelOrGprsId; db.station_online_info.InsertOnSubmit(online_info); } List <station_online_info> deletes = db.station_online_info.Where(c => c.stationid == online_info.stationid && c.id != online_info.id).ToList(); if (deletes.Count > 0) { db.station_online_info.DeleteAllOnSubmit(deletes); } } } db.SubmitChanges(); } catch (Exception ex) { LogMg.AddError("保存客户端在线数据时失败,\r\n" + ex.ToString()); } } } catch (Exception ex) { LogMg.AddError(ex); } Thread.Sleep(60000); } }
/// <summary> /// 拍照 /// </summary> /// <param name="client"></param> /// <param name="timeout"></param> public static bool TakePhoto(DTUClientInfo client, int timeout, ref byte[] imageBytes) { //这个方法主要包含三个步骤, //第一步:发送拍照指令 //第二步:发送“获取照片包数量”的指令 //第三步:循环去读取每一个照片包内容 byte[] rubbish = new byte[JBT_DTU.ReceiveLength]; byte packcount = 0x00; int n = 1; //当发送的命令没接收到,这个变量就会+1,直到他等于5 int commandLen1 = 0; byte[] command1 = GetTakePhotoCommand(ref commandLen1); try { client.socket.Receive(rubbish, JBT_DTU.ReceiveLength, SocketFlags.None); } catch (Exception) { } //第一步:发送拍照指令 JBT_DTU.SendUserData_Assistant(client.socket, command1, commandLen1, client.TelOrGprsId); while (n <= 5) { try { byte[] content = new byte[JBT_DTU.ReceiveLength]; int conLen = 0; byte type = new byte(); string tel = ""; Thread.Sleep(3000); bool flag = JBT_DTU.rdata(client.socket, timeout, ref content, ref conLen, ref type, ref tel); if (flag == false) { n++; continue; } if (type != JBT_DTU.DTU_to_Server_SendData_Assistant) { n++; continue; } if (conLen != 7) { n++; continue; } break; } catch (SocketException ex) { n++; LogMg.AddError(ex); } catch (Exception ex) { n++; LogMg.AddError(ex); } } DTU_ClientManager.UpdateLastVisitTime(client, DateTime.Now); if (n > 5) { return(false); //如果读取5次都读不到数据,就表示这次拍照失败 } LogMg.AddError("拍照命令 拍照次数=" + n); n = 1; int commandLen2 = 0; //第二步:发送“获取照片包数量”的指令 byte[] command2 = GetPicPackCountCommand(ref commandLen2); JBT_DTU.SendUserData_Assistant(client.socket, command2, commandLen2, client.TelOrGprsId); while (n <= 5) { try { byte[] content = new byte[4096]; int conLen = 0; byte type = new byte(); string tel = ""; Thread.Sleep(1000); bool flag = JBT_DTU.rdata(client.socket, timeout, ref content, ref conLen, ref type, ref tel); if (flag == false) { n++; continue; } if (type != JBT_DTU.DTU_to_Server_SendData_Assistant) { n++; continue; } if (conLen != 8) { n++; continue; } packcount = content[4]; break; } catch (SocketException ex) { n++; LogMg.AddError(ex); } catch (Exception ex) { n++; LogMg.AddError(ex); } } if (n > 5) { return(false); } LogMg.AddError("获取照片包数量 n=" + n); imageBytes = new byte[packcount * 1000]; int picIndex = 0; //第三步:循环去读取每一个照片包内容 for (byte i = 0x00; i < packcount; i++) { n = 1; int commandLen3 = 0; byte[] command3 = GetReadPictureCommand(i, ref commandLen3); JBT_DTU.SendUserData_Assistant(client.socket, command3, commandLen3, client.TelOrGprsId); while (n <= 5) { try { byte[] content = new byte[4096]; int conLen = 0; byte type = new byte(); string tel = ""; Thread.Sleep(1000); bool flag = JBT_DTU.rdata(client.socket, timeout, ref content, ref conLen, ref type, ref tel); if (flag == false) { n++; continue; } if (type != JBT_DTU.DTU_to_Server_SendData_Assistant) { n++; continue; } if (content[0] != HEAD || content[1007] != HEAD) // { n++; continue; } if (content[04] != i) //如果包号不对 { n++; continue; } Buffer.BlockCopy(content, 5, imageBytes, picIndex, 1000); picIndex += 1000; break; } catch (SocketException ex) { n++; LogMg.AddError(ex); LogMg.AddError("循环读取包 n=" + n); } catch (Exception ex) { n++; LogMg.AddError(ex); } } if (n > 5) { return(false); } } //ImageUtil.SaveFormBytes(imageBytes, GetImageLen(imageBytes)); //len = GetImageLen(imageBytes); return(true); }