|
|
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 { /// <summary>
/// edit by liuwz 2019-09-18 修改防止重复打印的方法
/// 打印任务
/// </summary>
[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<string, List<Content>>(); 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<Content> { newContent } ); } else dicPrints[row["PrintIP"].ToString()].Add(newContent); } //按打印机并行异步发送
Console.WriteLine($"{DateTime.Now.ToString()}:打印开始"); List<Task> taskList = new List<Task>(); foreach (KeyValuePair<string, List<Content>> 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; } }
/// <summary>
/// 异步发送打印任务
/// </summary>
/// <param name="p"></param>
private async Task Send(KeyValuePair<string, List<Content>> 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(); } }); }
/// <summary>
/// 异步回调方法
/// </summary>
/// <param name="asyncresult"></param>
private void CallBackMethod(IAsyncResult asyncresult) { //使阻塞的线程继续
TimeoutObject.Set(); }
} }
|