using MySql.Data.MySqlClient; using Quartz; using System; using System.Collections; using System.Collections.Generic; using System.Data; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; using System.Linq; using System.Threading; namespace POSCorePrint.Jobs { /// /// edit by liuwz 2019-09-18 修改防止重复打印的方法 /// 打印任务 /// [DisallowConcurrentExecution] public class PrintJob : IJob { private readonly ManualResetEvent TimeoutObject = new ManualResetEvent(false); private int Timeout = 2500;//连接打印机超时时间,毫秒。 private int TimeoutSend = 5000;//连接打印机超时时间,毫秒。 public Task Execute(IJobExecutionContext context) { //查询最近N分钟需要打印的数据,同时删除N天前的打印数据。 string sql = $@"select task.Id,task.content,print.PrintIP from pos_store_printtask task inner join pos_store_print print on task.code=print.Id where task.status = 0 and print.isdelete=0 and task.CreateTime >'{DateTime.Now.AddMinutes(-Constant.PrintBackTime).ToString("yyyy-MM-dd HH:mm:ss")}'; delete from pos_store_printtask where CreateTime <'{DateTime.Now.AddDays(-Constant.SaveHisDataDays).ToString("yyyy-MM-dd HH:mm:ss")}';"; // TODO 查询数据库获取打印任务列表 DataTable dataTable; try { dataTable = MySqlHelper.ExecuteDataset(Constant.ConnectionString, sql).Tables[0]; //无打印任务 if (dataTable.Rows.Count == 0) return Task.CompletedTask; //有打印任务,按打印机分组 var dicPrints = new Dictionary>(); foreach (DataRow row in dataTable.Rows) { var newContent = new Content() { ID = row["Id"].ToString(), ContentVal = row["Content"].ToString() }; if (!dicPrints.ContainsKey(row["PrintIP"].ToString())) { dicPrints.Add( row["PrintIP"].ToString(), new List { newContent } ); } else dicPrints[row["PrintIP"].ToString()].Add(newContent); } //按打印机并行异步发送 Console.WriteLine($"{DateTime.Now.ToString()}:打印开始"); List taskList = new List(); foreach (KeyValuePair> p in dicPrints) { taskList.Add(Send(p)); } //等所有异步打印完再返回 Task.WhenAll(taskList).Wait(); Console.WriteLine($"{DateTime.Now.ToString()}:打印结束"); return Task.CompletedTask; } catch (Exception ex) { Console.WriteLine($"{DateTime.Now.ToString()}:获取打印任务失败", ex); return Task.CompletedTask; } } /// /// 异步发送打印任务 /// /// private async Task Send(KeyValuePair> p) { string idSuccess = ""; string idFail = ""; await Task.Run(() => { IPAddress iPAddress = IPAddress.Parse(p.Key); IPEndPoint iPEndPoint = new IPEndPoint(iPAddress, Constant.port); Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); try { TimeoutObject.Reset(); socket.BeginConnect(iPEndPoint, CallBackMethod,socket); //阻塞当前线程              if (!TimeoutObject.WaitOne(Timeout, false)) { //处理连接不成功的动作 socket.Close(); Console.WriteLine($"{DateTime.Now.ToString()}: 打印失败:{p.Key}【连接超时】"); return; } if (!socket.Connected) { //处理连接不成功的动作 socket.Close(); Console.WriteLine($"{DateTime.Now.ToString()}: 打印失败:{p.Key} socket【连接超时】"); return; } foreach (Content content in p.Value) { ////判断打印机状态:是否在线,是否有纸 //byte[] dataSatus = new byte[3]; //for (int i = 0; i < dataSatus.Length; i++) //{ // dataSatus[i] = byte.Parse(content.ContentVal.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber); //} //int iRes = socket.Send(dataSatus, 0); //打印内容 byte[] data = new byte[content.ContentVal.Length / 2]; try { for (int i = 0; i < data.Length; i++) { data[i] = byte.Parse(content.ContentVal.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber); } } catch (Exception ex) { Console.WriteLine($"{DateTime.Now.ToString()}:转换打印数据失败 {ex.Message}", ex); } try { //byte[] mData = new byte[data.Length]; //Array.Copy(data, 0, mData, 0, data.Length); SocketError errorCode; //edit by liuwz 2020-04-03 增加超时 socket.SendTimeout= TimeoutSend; int iResult = socket.Send(data, 0, out errorCode); //add by liuwz 2020-01-13增加打印发送长度判断。 if (SocketError.Success != errorCode || iResult !=data.Length) { //add by liuwz 2019-11-29失败时增加打印次数。 idFail += string.IsNullOrEmpty(idFail) ? $"'{content.ID}'" : $",'{content.ID}'"; Console.WriteLine($"{DateTime.Now.ToString()}: ip:{p.Key},id:{content.ID} 打印返回失败:【{errorCode.ToString()}】"); } else idSuccess += string.IsNullOrEmpty(idSuccess) ? $"'{content.ID}'" : $",'{content.ID}'"; } catch (Exception ex) { //add by liuwz 2019-11-29失败时增加打印次数。 idFail += string.IsNullOrEmpty(idFail) ? $"'{content.ID}'" : $",'{content.ID}'"; Console.WriteLine($"{DateTime.Now.ToString()}: ip:{p.Key},id:{content.ID} 发送打印命令失败:【{ex.Message}】", ex); } } // 操作数据库更新状态 if (!string.IsNullOrEmpty(idSuccess)) { var sql = $"update pos_store_printtask set status=1,PrintTime=NOW(),PrintTimes=ifnull(PrintTimes,0)+1 where Id in({idSuccess});"; Console.WriteLine($"{DateTime.Now.ToString()}:打印成功更新记录:{iPAddress};{idSuccess}"); MySqlHelper.ExecuteNonQueryAsync(Constant.ConnectionString, sql); } if (!string.IsNullOrEmpty(idFail)) { Console.WriteLine($"{DateTime.Now.ToString()}:打失败更新记录:{iPAddress};{idFail}"); var sql = $"update pos_store_printtask set PrintTimes=ifnull(PrintTimes,0)+1 where Id in({idFail});"; MySqlHelper.ExecuteNonQueryAsync(Constant.ConnectionString, sql); } } catch (Exception ex) { Console.WriteLine($"{DateTime.Now.ToString()}: 打印失败:{p.Key}【{ex.Message}】{string.Join('|',p.Value.Select(m=>new {m.ID}))}", ex); } finally { socket.Close(); } }); } /// /// 异步回调方法  /// /// private void CallBackMethod(IAsyncResult asyncresult) { //使阻塞的线程继续           TimeoutObject.Set(); } } }