using BayonetTransfer.Common.Json;
using Newtonsoft.Json;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace BayonetTransfer
{
internal class Program
{
///
/// 接收到的卡口数据缓存
///
private static ConcurrentDictionary List_Bayonet { get; set; }
///
/// 卡口数据保存计时器
///
private static System.Timers.Timer UploadTimer { get; set; }
///
/// 卡口数据保存线程
///
private static System.Threading.Thread UploadThread { get; set; }
public delegate bool ControlCtrlDelegate(int CtrlType);
[DllImport("kernel32.dll")]
private static extern bool SetConsoleCtrlHandler(ControlCtrlDelegate HandlerRoutine, bool Add);
private static ControlCtrlDelegate cancelHandler = new ControlCtrlDelegate(HandlerRoutine);
public static bool HandlerRoutine(int CtrlType)
{
switch (CtrlType)
{
case 0:
Console.WriteLine("0工具被强制关闭"); //Ctrl+C关闭
break;
case 2:
Console.WriteLine("2工具被强制关闭");//按控制台关闭按钮关闭
break;
}
Console.ReadLine();
return false;
}
static void Main(string[] args)
{
SetConsoleCtrlHandler(cancelHandler, true);
List_Bayonet = new ConcurrentDictionary();
//数据上传定时器
UploadTimer = new System.Timers.Timer(1 * 60 * 1000);
//注册定时器执行事件方法
UploadTimer.Elapsed += UploadTimer_Elapsed;
//启动定时器
UploadTimer.Start();
try
{
//启动RabbitMQ消息队列接收服务
Subcribe();
}
catch (Exception ex)
{
Console.Write(string.Format("RabbitMQ连接异常:{0}\n", ex.ToString()));
}
Console.ReadKey();
}
///
/// 上传定时器方法
///
///
///
private static void UploadTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (UploadThread == null || !UploadThread.IsAlive)
{
UploadThread = new System.Threading.Thread(() =>
{
try
{
UploadDataToSerive();
}
catch (Exception ex)
{
Console.WriteLine($"卡口数据上传失败:{ex.Message}");
Common.LoggerHelper.WriteLogger($"卡口数据上传失败:{ex.ToString()}");
}
})
{ IsBackground = true };
UploadThread.Start();
}
}
///
/// 启动RabbitMQ消息队列接收服务
///
private static void Subcribe()
{
string str_HostName = ConfigurationManager.AppSettings["HostName"];
string str_Port = ConfigurationManager.AppSettings["Port"];
string str_UserName = ConfigurationManager.AppSettings["UserName"];
string str_Password = ConfigurationManager.AppSettings["Password"];
//实例化一个连接工厂和其配置为使用所需的主机,虚拟主机和证书(证书)
ConnectionFactory factory = new ConnectionFactory
{
HostName = str_HostName,//"112.30.55.253",//RabbitMQ主机服务地址
Port = int.Parse(str_Port),//5672,//RabbitMQ主机服务端口
UserName = str_UserName,//"yishang",//用户名
Password = str_Password,//"Yishang%2022",//密码
VirtualHost = "/"//默认情况可省略此行
};
//创建一个AMQP 0-9-1连接
using (IConnection connection = factory.CreateConnection())
{
//创建一个AMQP 0-9-1频道,该对象提供了大部分 的操作(方法)协议。
using (IModel channel = connection.CreateModel())
{
#region 定义队列、交换器并绑定
//队列
channel.QueueDeclare("yishang", true, false, false, null);
//交换器
channel.ExchangeDeclare("entrance_flow_exchange", ExchangeType.Fanout, true, false, null);
//绑定
channel.QueueBind("yishang", "entrance_flow_exchange", "RoutingKey", null);
#endregion
Console.WriteLine("卡口数据接收服务已准备就绪~~");
//消费者
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var body = ea.Body;
var message = Encoding.UTF8.GetString(body.ToArray());
string str_Key = Guid.NewGuid().ToString("N");
try
{
var bayonet = JsonConvert.DeserializeObject(message, new JsonSerializerSettings() { ContractResolver = new OcrWriteResolver() });
List_Bayonet.AddOrUpdate(str_Key, bayonet, (key, bay) => bayonet);
Console.WriteLine($"[{bayonet.InOut_Time}]{bayonet.License_Plate},{bayonet.Serverpart_Name}{bayonet.Serverpart_Region}");
}
catch (Exception ex)
{
Common.LoggerHelper.WriteLogger($"卡口数据接收解析异常,GUID:{str_Key},接收到的数据:{message},错误信息:{ex.Message}");
}
};
//自动ack消费
channel.BasicConsume("yishang", true, consumer);
Console.ReadLine();
}
}
}
///
/// 保存接收到的卡口数据到服务器
///
private static void UploadDataToSerive()
{
//接口地址
string str_ApiURL = ConfigurationManager.AppSettings["ApiURL"];//"http://openapi.eshangtech.com:7080/WebApi/BigData/AddBayonet"
Console.WriteLine("接口地址:" + str_ApiURL);
//定义上传到接口的数据列表
List list_ApiBayonet = new List();
//定义已处理的卡口数据列表Key,在数据上传成功后,移除数据缓存
List str_Remove = new List();
Console.WriteLine($"【{DateTime.Now}】开始上传卡口数据到服务器");
//记录文本日志
Common.LoggerHelper.WriteLogger("开始上传卡口数据到服务器");
//从缓存中取出全部需要处理的数据
foreach (var model in List_Bayonet.ToArray())
{
//停留时长
int.TryParse(model.Value.Stay_Times, out int int_StayTimes);
//转换为接口数据格式
list_ApiBayonet.Add(new Model.ApiBayonetModel
{
Serverpart_Name = model.Value.Serverpart_Name,
Serverpart_Region = model.Value.Serverpart_Region,
InOut_Type = model.Value.InOut_Type,
InOut_Time = long.Parse(model.Value.InOut_Time.ToString("yyyyMMddHHmmss")),
Vehicle_Type = model.Value.Vehicle_Type,
License_Plate = model.Value.License_Plate,
Vehicle_Speed = model.Value.Vehicle_Speed,
Stay_Times = int_StayTimes,
Bayonet_Desc = model.Value.Bayonet_Desc
});
//添加待移除数据Key到列表
str_Remove.Add(model.Key);
}
//记录文本日志
Common.LoggerHelper.WriteLogger($"本次接收{list_ApiBayonet.Count}条卡口流水");
//每次上传的数据量(经过测试,安徽卡口抓拍数量,每分钟最大值在400条左右,
//Api接口每秒处理数据量在100条左右,综合后设定每次最大上传500条,以保证接口稳定和数据及时性)
int int_Size = 500;
//缓存数据分页
int int_PageCount = (int)Math.Ceiling((decimal)list_ApiBayonet.Count / int_Size);
for (int i = 0; i < int_PageCount; i++)
{
//取分页数据
var list_Temp = list_ApiBayonet.Skip(i * int_Size).Take(int_Size).ToList();
//拼接接口参数字符串
string str_PostData = JsonConvert.SerializeObject(list_Temp);
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Start();
try
{
//调用接口并解析返回的数据
string str_Result = Common.HttpHelper.HttpPost(str_PostData, str_ApiURL, "application/json", 120);
//解析接口返回值
Model.ResultDataModel rm_ResultModel = JsonConvert.DeserializeObject>(str_Result);
sw.Stop();
//数据上传成功
if (rm_ResultModel.Result_Code == 100)
{
//删除已上传的缓存数据
str_Remove.ForEach(p => List_Bayonet.TryRemove(p, out _));
Console.WriteLine($"卡口数据上传成功。本次上传{list_Temp.Count}条;用时:{sw.Elapsed.TotalSeconds}秒");
//记录文本日志
Common.LoggerHelper.WriteLogger($"卡口数据上传成功。本次上传{list_Temp.Count}条");
}
else
{
Console.WriteLine($"卡口数据上传失败,接口错误信息:[{rm_ResultModel.Result_Code}]{rm_ResultModel.Result_Desc}");
//记录文本日志
Common.LoggerHelper.WriteLogger($"卡口数据上传失败,接口错误信息:[{rm_ResultModel.Result_Code}]{rm_ResultModel.Result_Desc}");
//记录文本日志
Common.LoggerHelper.WriteLogger($"发送到Api接口的数据:{str_PostData}");
}
}
catch (Exception ex)
{
Console.WriteLine($"卡口数据上传失败,错误信息:{ex.Message}");
Common.LoggerHelper.WriteLogger($"卡口数据上传失败,错误信息:{ex.Message}");
Common.LoggerHelper.WriteLogger($"发送到Api接口的数据:{str_PostData}");
}
}
//记录文本日志
Common.LoggerHelper.WriteLogger($"卡口流水传输结束");
}
}
}