【问题标题】:Is this server solution optimal? [closed]这个服务器解决方案是最优的吗? [关闭]
【发布时间】:2021-04-11 00:49:36
【问题描述】:

我创建了从传感器接收数据(大约 80k 个样本/秒)并通过 TCP/IP 将它们发送到我的 PC 应用程序的设备。问题是有时我的设备会丢失一些数据。我想这是因为当我通过 TCP/IP 处理器发送数据时需要一些时间来做到这一点,然后他有一段时间没有从传感器接收数据。我注意到,当我在发送之前收集一些数据时发生的频率较低,所以我在 data.Length 大于 30000 时发送数据。感谢您的建议。 有我的服务器代码:

while (true)
{
    if (ClientIsConnected==1)
    {
        value = Convert.ToString(sensor1.Read(0)); ; // Publish the return value 

        DateTime currentDate = DateTime.Now;
        long elapsedTicks = currentDate.Ticks - startDate.Ticks;
        TimeSpan elapsedSpan = new TimeSpan(elapsedTicks);
        time = Convert.ToString(elapsedTicks / 100);

        data.Append("[" + value + " " + time + "]" + "/n");
        if (data.Length > 30000)
        {
            serverTcp.Send(socket, Convert.ToString(data));
            data.Clear();
        }
    }   
}

编辑两个不同的线程代码:

object msg = null;

if (ClientIsConnected==1)
{
    var threadTcp = new Thread(() =>
    {
        server.Send(socket, Convert.ToString(data));
    });

    var threadReadAdc = new Thread(() =>
    {
        value = Convert.ToString(Sensor1.Read(0)); ; // Publish the return value
      
        DateTime currentDate = DateTime.Now;
        long elapsedTicks = currentDate.Ticks - startDate.Ticks;
        TimeSpan elapsedSpan = new TimeSpan(elapsedTicks);
        time = Convert.ToString(elapsedTicks / 100);

        data = data.Append("[" + value + " " + time + "]" + "\n");
        if (data.Length > 30000)
        {
            msg = Convert.ToString(data);
            data.Clear();
        }
    });
    
    threadReadAdc.Start();
    threadTcp.Start();
}

【问题讨论】:

  • 我假设有问题的传感器仅在询问时给出读数(它不缓冲?),如果是这样,您需要一个专用于以固定间隔读取并缓冲结果,以及专用于按计划或以阈值读数发送缓冲结果的结果。您需要代表传感器缓冲数据。
  • 是的,传感器仅在询问时读取。所以我必须创建两个不同的线程。第一个必须负责读取数据,第二个负责发送?
  • @Charleh 谢谢你的回答我创建了两个不同的线程。我添加了我的新代码作为编辑。你能解释一下我现在做错了什么吗?如何同步这些线程?

标签: c# tcp tcpserver


【解决方案1】:

我会在这里使用BlockingCollection<string> 之类的东西

https://docs.microsoft.com/en-us/dotnet/api/system.collections.concurrent.blockingcollection-1?view=net-5.0

您可以设置字符串集合,在一个线程中写入该集合,并在另一个线程中读取。读取可以将结果存储在缓冲区中,并在缓冲区足够满时通过 TCP 发送(或经过足够的时间 - 这取决于您)。

阻塞集合是线程安全的,读取会阻塞,直到有东西要读取。

例如


var data = new BlockingCollection<string>();

Task taskWrite = Task.Run(() =>
{
    while(true)
    {
        var sensorReading = Convert.ToString(sensor1.Read(0)); // Do your string time/formatting here too - I left it off for clarity
        data.Add(sensorReading);
    }
});

Task taskRead = Task.Run(() => {
    var buffer = List<string>();

    while(true)
    {
        if(buffer.Count > 30000) 
        {
            // Grab contents of buffer and send via TCP
            server.Send(socket, String.Join("\n", buffer));
            buffer.Clear();
        }
        else 
        {
            // Consume the next sensor value from the collection
            buffer.Add(data.Take());
        }
    }
});

如果您想确保不会用值填满内存(例如,如果您的读取速度比写入速度快得多),您还可以设置阻塞集合的边界。

【讨论】:

  • 非常感谢,我从你的回答中学到了很多。你帮助我理解了多线程是如何工作的。不幸的是,我仍然在丢失数据,但这不再是服务器的错。我现在将检查客户端。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-15
  • 1970-01-01
  • 2016-09-10
  • 2023-04-07
  • 2012-12-06
  • 2021-03-11
  • 1970-01-01
相关资源
最近更新 更多