using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
namespace Seyounth.Auto.Hs.Runtime.Scanner
{
///
/// 料箱扫码枪
///
public class BoxScanner : IScanner
{
public int Id => 2;
//扫到码后的业务逻辑
public event Action OnScanned;
private DeviceConnectConfig DeviceConnectConfig;
private TcpClient _tcp;
//字节流、可以理解为后端与扫码枪之间的一条管道,扫码枪的数据就是通过这条管道发送给我们的
private NetworkStream _stream;
private readonly IServiceProvider serviceProvider;
private readonly IEnumerable scannerEventHandles;
private readonly ILogger logger;
private CancellationTokenSource _receiveDataCancellationToken;
private CancellationTokenSource _cts = new CancellationTokenSource();
public BoxScanner(IConfiguration configuration, IServiceProvider serviceProvider,IEnumerable scannerEventHandles,ILogger logger)
{
/*
* 从配置文件获取扫码枪IP/端口
*/
var configs = configuration.GetSection("Scanner").Get();
if (configs is not null && configs.Length > 0)
{
DeviceConnectConfig = configs.FirstOrDefault(e => e.Id == Id);
}
this.serviceProvider = serviceProvider;
this.scannerEventHandles = scannerEventHandles;
this.logger = logger;
}
///
/// 连接扫码枪
///
///
public async Task ConnectAsync()
{
while (true)
{
if (_tcp is not null)
{
try
{
_tcp.Dispose();
}
catch (Exception ex)
{
/*
* 忽略释放异常
*/
}
}
_tcp = new TcpClient();
try
{
await _tcp.ConnectAsync(new IPEndPoint(IPAddress.Parse(DeviceConnectConfig.IP), DeviceConnectConfig.Port));
if (_stream is not null)
_stream.Dispose();
_stream = _tcp.GetStream();
logger.LogInformation("箱扫码枪连接成功,开始接收数据");
_receiveDataCancellationToken?.Cancel();
_receiveDataCancellationToken = new CancellationTokenSource();
ReceiveData(_receiveDataCancellationToken.Token);
break;
}
catch (Exception ex) when (ex.GetBaseException() is OperationCanceledException oce || ex.GetBaseException() is SocketException socketException)
{
await Task.Delay(1000 * 5);
logger.LogError(ex.GetBaseException(), "箱扫码枪连接失败,尝试重连中");
continue;
}
catch (Exception ex)
{
logger.LogError(ex, "箱扫码枪连接失败");
}
}
}
///
/// 接收扫码枪数据
///
///
private async Task ReceiveData(CancellationToken cancellationToken)
{
try
{
while (!cancellationToken.IsCancellationRequested)
{
//一次最大读取1M
byte[] buffer = new byte[1024];
/* readCount :实际读取字节数*/
var readCount = _stream.Read(buffer, 0, buffer.Length);
if (readCount <= 0)
throw new SocketException();
/* UTF-8 编码获取字符串*/
var result = Encoding.UTF8.GetString(buffer, 0, readCount);
if (string.IsNullOrWhiteSpace(result)) continue;
logger.LogInformation($"箱扫码枪接收数据:{result},字节数:{readCount}");
/* 异步执行所有事件避免事件中报错未能执行完成所有事件而阻塞下次接收 */
var handles = serviceProvider.GetService>();
foreach (var item in handles)
{
await item.ExecAsync(result, Id);
}
}
}
catch (Exception ex) when (ex.GetBaseException() is OperationCanceledException oce || ex.GetBaseException() is SocketException socketException)
{
logger.LogError(ex.GetBaseException(), "箱扫码枪连接失败,尝试重连中");
await ConnectAsync();
}
catch (Exception ex)
{
logger.LogError(ex, "箱扫码枪连接失败");
}
}
///
/// 断开连接
///
///
public Task DisconnectAsync()
{
_receiveDataCancellationToken?.Cancel();
_tcp?.Dispose();
return Task.CompletedTask;
}
}
}