2025-03-28 09:49:56 +08:00

245 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
{
/// <summary>
/// 接收到的卡口数据缓存
/// </summary>
private static ConcurrentDictionary<string, Model.BayonetModel> List_Bayonet { get; set; }
/// <summary>
/// 卡口数据保存计时器
/// </summary>
private static System.Timers.Timer UploadTimer { get; set; }
/// <summary>
/// 卡口数据保存线程
/// </summary>
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<string, Model.BayonetModel>();
//数据上传定时器
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();
}
/// <summary>
/// 上传定时器方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
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();
}
}
/// <summary>
/// 启动RabbitMQ消息队列接收服务
/// </summary>
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<Model.BayonetModel>(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();
}
}
}
/// <summary>
/// 保存接收到的卡口数据到服务器
/// </summary>
private static void UploadDataToSerive()
{
//接口地址
string str_ApiURL = ConfigurationManager.AppSettings["ApiURL"];//"http://openapi.eshangtech.com:7080/WebApi/BigData/AddBayonet"
Console.WriteLine("接口地址:" + str_ApiURL);
//定义上传到接口的数据列表
List<Model.ApiBayonetModel> list_ApiBayonet = new List<Model.ApiBayonetModel>();
//定义已处理的卡口数据列表Key在数据上传成功后移除数据缓存
List<string> str_Remove = new List<string>();
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<string> rm_ResultModel = JsonConvert.DeserializeObject<Model.ResultDataModel<string>>(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($"卡口流水传输结束");
}
}
}