有一个问题困扰着我。有一个 GPS 跟踪器,它使用自己的协议通过 TCP / IP 传输数据。我正在编写一个后台服务(.NET Core 3.1),它应该侦听 tcp 端口并将消息包以原始形式(字节 [] 或编码为字符串)保存到数据库中。现在我的 tcp 端口嗅探代码如下所示:
public class TcpListenerBackgroundService : BackgroundService
{
private readonly ITcpListenerWrapper _tcpListener;
private readonly ILogger<TcpListenerBackgroundService> _logger;
public TcpListenerBackgroundService(ITcpListenerWrapper tcpListener, ILogger<TcpListenerBackgroundService> logger)
{
_tcpListener = tcpListener;
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await _tcpListener.StartListeningAsync(stoppingToken);
}
}
TcpListenerWrapper.cs
public sealed class TcpListenerWrapper : ITcpListenerWrapper, IDisposable
{
private const int BufferSize = 1024;
private readonly TcpListener _listener;
private readonly IMessageManager _messageManager;
public TcpListenerWrapper(ITcpListenerWrapperConfiguration config, IMessageManager messageManager)
{
_listener = new TcpListener(IPAddress.Any, config.PortNumber);
_messageManager = messageManager;
}
public async Task StartListeningAsync(CancellationToken stoppingToken)
{
_listener.Start();
while (!stoppingToken.IsCancellationRequested)
{
var client = await _listener.AcceptTcpClientAsync();
var stream = client.GetStream();
while (!stoppingToken.IsCancellationRequested)
{
var buffer = new byte[BufferSize];
using (var ms = new MemoryStream())
{
int numBytesRead;
while ((numBytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, numBytesRead);
}
if (ms.Length > 0)
{
var messageAsText = Encoding.ASCII.GetString(buffer);
// Console.WriteLine($"New message received: {messageAsText}");
var message = _messageManager.CreateMessage(buffer);
message.Save(); // Сохранение в бд.
}
}
}
}
}
public void Dispose()
{
_listener.Stop();
}
}
让 GPS 追踪器以 1 分钟的周期发送 10 个数据包。
问题:是否有可能NetworkStream
一次有多个包(比如 3 个包)?或者有保证他们会一次来一个吗?
添加。问题:消息监听代码是否有错误?也许这里缺少一些东西,或者反之亦然,太多了?
.NET 不知道(也不应该)某种 GPS 跟踪器正在那里传输数据。随着字节的到来,它们将被添加。也就是说,理论上,可以先来两个半包,然后再来一个半包。也许以另一种方式。TCP 以字节为单位运行。并且该协议仅保证字节(字节!)将以相同的顺序到达,不会出现“意外丢失的字节/位”。此外,协议将尝试传递数据包,或者如果无法传递(线路被切断),将“断开连接”。
看了看代码。您正在尝试将每个传入数据包解码为完全传入的数据包。但只有这一点是有保证的。是的,通过本地测试,它很可能通常以这种方式工作。但是,一旦 Windows 决定气馁(防病毒程序已启动)或路由器 / gsm 模块后面的网络。它可以是任何东西。
我有一个案例,由于一个众所周知的防火墙,第一次读取总是第一个字节。然后一切照常。但他并没有一直这样做。代码中的程序员期望立即需要至少 4 个字节。和不...
在代码中做什么。在这个协议中,消息分隔符很可能是换行符。因此,数据来了,添加到缓冲区的末尾,然后寻找换行符。是的 - 提取包,重复搜索。否 - 直到下一个包裹。