首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >AsyncTCP C# -arduino/统一通信

AsyncTCP C# -arduino/统一通信
EN

Stack Overflow用户
提问于 2022-01-31 18:13:18
回答 1查看 210关注 0票数 1

过去几周,我一直在使用tcp协议来使用以下代码将数据包从arduino发送到一致性:

代码语言:javascript
复制
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;

public class TCPConnection : MonoBehaviour
{
    public string IP_Seat = "192.168.137.161";  
    public int port = 34197;
    #region private members     
    private TcpClient socketConnection;
    private Thread clientReceiveThread;
    public float a, b, c, vel;
    public float test = 0.0f;
    #endregion
    // Use this for initialization  
    void Awake()
    {
        ConnectToTcpServer();
    }
    
    /// <summary>   
    /// Setup socket connection.    
    /// </summary>  
    private void ConnectToTcpServer()
    {
        try
        {
            clientReceiveThread = new Thread(new ThreadStart(ListenForData));
            clientReceiveThread.IsBackground = true;
            clientReceiveThread.Start();
        }
        catch (Exception e)
        {
            Debug.Log("On client connect exception " + e);
        }
    }
    /// <summary>   
    /// Runs in background clientReceiveThread; Listens for incoming data.  
    /// </summary>     
    private void ListenForData()
    {
        var aold = 0.0f;
        var bold = 0.0f;
        var cold = 0.0f;
        var velold = 0.0f;
        try
        {
            socketConnection = new TcpClient(IP_Seat, port);
            //cketConnection.ConnectAsync(IP_Seat, port);  // non si connette
            //socketConnection.Client.Blocking = false;
            //socketConnection.Client.ConnectAsync(IP_Seat,port);
            Byte[] bytes = new Byte[16];
            while (socketConnection.Connected)
            {
                // Get a stream object for reading              
                using (NetworkStream stream = socketConnection.GetStream())
                {
                    int length;
                    // Read incoming stream into byte arrary.                   
                    while ((length = stream.Read(bytes, 0, bytes.Length)) != 0)
                    {
                        //Debug.Log("I'm receiving Data");
                        if (length == 16)
                        {
                            //Debug.Log("I'm receiving len 16 and I like it");
                            var incomingData = new byte[length];
                            var A = new Byte[4];
                            var B = new Byte[4];
                            var C = new Byte[4];
                            var VEL = new Byte[4];

                            Array.Copy(bytes, 0, incomingData, 0, length);
                            // Convert byte array to string message.                        
                            string serverMessage = Encoding.ASCII.GetString(incomingData);
                             Array.Copy(bytes, 0, A, 0, 4);
                             Array.Copy(bytes, 4, B, 0, 4);
                             Array.Copy(bytes, 8, C, 0, 4);
                             Array.Copy(bytes, 12, VEL, 0, 4);



                            a = BitConverter.ToSingle(A, 0) < 0 ? BitConverter.ToSingle(A, 0) : aold;
                            b = BitConverter.ToSingle(B, 0) < 0 ? BitConverter.ToSingle(B, 0) : bold;
                            c = BitConverter.ToSingle(C, 0) < 0 ? BitConverter.ToSingle(C, 0) : cold;
                            vel = BitConverter.ToSingle(VEL, 0); //< 0 ? BitConverter.ToSingle(C, 0) : 0;

                            //Debug.Log("server message received as: " + serverMessage +a +" "+b + " " + c + " " + vel);

                            aold = a;
                            bold = b;
                            cold = c;
                            velold = vel;

                        }
                        else {
                            //evitare che bilancia aspetti ack di tcp
                        }
                    }

                }
            }
        }
        catch (SocketException socketException)
        {
            Debug.Log("Socket exception: " + socketException);
        }
    }

}

现在,我遇到了阻塞问题:我想对TCP使用异步方法,但是对tcpClient.ConnectAsync使用异步方法,但是它返回一个SocketEXception,我不知道为什么。

arduino以16字节分组发送4块浮点数,其中98-99%到达正确,但丢失的1-2%会导致系统阻塞和不良行为(因为我正在编写设备,所以不需要延迟等待ack或数据包)。

我如何使这个sokcet异步?

编辑:使用Net4.X:如何在这个脚本中使用connectASync(ip,端口)方法?

EN

回答 1

Stack Overflow用户

发布于 2022-01-31 19:32:35

如前所述,TCP只是一个未定义的数据流,您需要实现一个根据协议来知道消息何时结束(完全接收)和何时启动。

现在,在您的例子中,您似乎已经知道您有确切的16字节。

然而,NetworkStream.Read不一定要等到实际接收到的16字节。如果由于某种原因(网络中的延迟),此时调用它时,流中的字节较少,那么它将只接收可用的数量。

现在假设您的发送方发送3个包( 16字节)(所以是48字节)。

可能发生的情况是,您第一次只读取8个字节。从现在开始,每一次读取调用都接收16个字节。=> 结果:您得到两个完整的缓冲区,即,但是有无效数据的,因为您总是在消息的中间开始读取。

注意Read的第二个参数

代码语言:javascript
复制
int offset -> The location in buffer to begin storing the data to.

您想要做的是等到缓冲区实际上已经满了,例如

代码语言:javascript
复制
var receivedBytes = 0;
while (receivedBytes < bytes.Length)
{
    receivedBytes +=  stream.Read(bytes, receivedBytes, bytes.Length - receivedBytes);
}

// Use bytes

现在,在继续之前,这将完全填充一个16字节缓冲区,因为在增加偏移量的同时,我们也减少了要读取的最大字节数。

另一个注意事项:您有大量的冗余数组创建、复制和BitConverter正在进行!

我宁愿用

代码语言:javascript
复制
var bytes = new byte[16];
var floats = new float[4];

之后,在接收到字节后,执行

代码语言:javascript
复制
Buffer.BlockCopy(bytes, 0, floats, 0, 16);

这将字节复制到浮动中,直接在下位字节层中。

然后你就可以简单地

代码语言:javascript
复制
a = floats[0] < 0 ? floats[0] : aold;
b = floats[1] < 0 ? floats[1] : bold;
c = floats[2] < 0 ? floats[2] : cold;
v = floats[3];

注:打电话,但我希望这个想法能弄清楚

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70930840

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档