【问题标题】:Can't transfer all my pixel data through UDP (WiFi)无法通过 UDP (WiFi) 传输我的所有像素数据
【发布时间】:2021-09-08 02:28:00
【问题描述】:

我正在尝试使用 UDP 和 TCP 协议通过 Wifi 将 Adafruit ESP32 Feather 中连续随机生成的像素颜色 (80x60) 发送到我的 C# 程序。我可以通过任何协议毫无问题地发送任何其他类型的数据,但是我创建的这个发送 4800 (80x60) 值的字符串会造成一些困难,尤其是在 UDP 中。

在 TCP 协议中,所有数据都由 ESP32 发送并由 C# 程序接收,尽管该协议非常慢,因此它们获得的视频每秒帧数很少。 在 UDP 的情况下,预计会更快(这是我的巨大希望),生成的数据并没有完全被 C# 程序接收,并且视频只有第一个像素(大约 410 - See Image

两种协议在 C# 程序中的定义方式相同,只是 TCP 是 Stream 格式,而 UDP 是 Datagrams(无法定义 Stream):

public void initiate_connection(string esp32_ip, string esp32_port, int protocoltype)
    {
        string msg;
        int port;


        if (protocoltype == 1)
        {
            protype = ProtocolType.Udp;
             socktype = SocketType.Dgram;   
        }
        else if (protocoltype == 2)
        {
            protype = ProtocolType.Tcp;           
            socktype = SocketType.Stream;
        }
        try
        {
            s = new Socket(AddressFamily.InterNetwork, socktype, protype);
            msg = esp32_ip;
            IPAddress adafruit_remote_IP = IPAddress.Parse(msg);
            port = int.Parse(esp32_port);
            IPEndPoint IP_Endpoint_remote = new IPEndPoint(adafruit_remote_IP, port);
             s.Connect(IP_Endpoint_remote);
        }
        catch (SocketException se)
        {
            MessageBox.Show(se.Message);
        }
        catch (ArgumentNullException se)
        {
            MessageBox.Show(se.Message);
        }
        catch (ObjectDisposedException se)
        {
            MessageBox.Show(se.Message);
        }
        catch (InvalidOperationException se)
        {
            MessageBox.Show(se.Message);
        }
        catch (System.Security.SecurityException se)
        {
            MessageBox.Show(se.Message);
        }
    }

    private string send_command_adafruit(string msg)
    {

        byte[] sent_data;
        byte[] received_data = new byte[10000];               //256

        int number_of_received_bytes;


        try
        {
            if (s.Connected)
             {
                 sent_data = System.Text.ASCIIEncoding.ASCII.GetBytes(msg);
                 s.Send(sent_data);
                 number_of_received_bytes = s.Receive(received_data);
                 msg = System.Text.Encoding.ASCII.GetString(received_data, 0, number_of_received_bytes);
                 //  s.Close();
                 return msg;
             } 
            else
            {
                MessageBox.Show("Application Message: Socket NOT connect, verify your cables and conections.");
                return "-1";
            }
        }
        catch (SocketException se)
        {
            MessageBox.Show(se.Message);
            return "-1";
        }
        catch (ArgumentNullException se)
        {
            MessageBox.Show(se.Message);
            return "-1";
        }
        catch (ObjectDisposedException se)
        {
            MessageBox.Show(se.Message);
            return "-1";
        }
        catch (System.Security.SecurityException se)
        {
            MessageBox.Show(se.Message);
            return "-1";
        }
    }

另一方面,我在 ESP32 中的代码如下:

#include <WiFi.h>
#include <WiFiClient.h>
#include <WiFiAP.h>
#include <WiFiUdp.h>
#include <Udp.h>


const char* ssid = "SensorIR_test";
const char* password = "123456789"; 

WiFiServer server(80);

WiFiUDP Udp;
const int udpPort = 80;      // local port to listen on
int reply;      // a int to send back
String str_reply, inputs;
String str_reply_UDP[60];
int speedx;

String parameter[6];
int i, j;
int subS_l;
int index_of_S;

void setup() {

Serial.begin(250000);


delay(10);

Serial.print("Setting AP (Access Point)…");
WiFi.softAP(ssid, password);
IPAddress IP = WiFi.softAPIP();
Serial.print("AP IP address: ");
Serial.println(IP);

server.begin();
Udp.begin(udpPort);

}

void loop() {
WiFiClient client = server.available();   // Listen for incoming clients
int packetSize = Udp.parsePacket();   
inputs = "";
i=1;
j=1;

if (client) {    
 
 // If a new client connects,
Serial.println("New Client.");          // print a message out in the serial port
while (client.connected()) {            // loop while the client's connected
  if (client.available()) {             // if there's bytes to read from the client,



   client.setNoDelay(1);

 //break;

 int c=client.read();
   
   //   else {
 // teste=teste+1;

  for (int y=0; y<60; y++) {
     for (int k=0; k<80; k++) {
     //speedx=random(0,255);
     str_reply+=random(0,255);
     str_reply+=" ";
      }
   client.print(str_reply);
   Serial.print(str_reply);
   client.print(" ");       
   Serial.print(" ");
   }
   
    //  delay(1000);
   }
   }
    // Close the connection
   client.stop();
   Serial.println("TCP communication disconnected.");
   Serial.println("");
   }
   else if (packetSize) {
   //  teste=teste+1;
   for (int y=1; y<61; y++) {
   str_reply_UDP[y]="";
   }


   int d = Udp.read();
   // Serial.println(d);
   if (d==59) {    //ASCII=";"
   Serial.println("New UDP Client.");          // print a message out in the serial port
   }

   else if (d==33)  {   //ASCII="!"

  for (int y=0; y<60; y++) {
     for (int k=0; k<80; k++) {
     str_reply_UDP[y]+=random(0,255);
     str_reply_UDP[y]+=" ";
  }
  }
  
  

//  str_reply+=" ";
  
   }

 //  Serial.println(str_reply);
 

Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());

for (int u=0; u<61; u++) {
  Serial.println(str_reply_UDP[u]);
  Udp.println(str_reply_UDP[u]);
}
//////Udp.println(str_reply);

Udp.endPacket();  
} 

}

有人知道我应该怎么做吗?

【问题讨论】:

    标签: c# sockets udp esp32


    【解决方案1】:

    看起来像是 MTU 问题。假设单个颜色像素为 3 B,则这 410 个像素加起来为 410x3=1230 B,接近单​​个网络帧的最大大小,略小于 1500B。虽然底层 IP 协议本身支持 UDP 数据包的分段(即将一个数据包分割成 MTU 大小的块),但 ESP32 中的简化网络堆栈可能不支持它。即便如此,出于可靠性和性能方面的原因,您也不希望对 UDP 数据包进行分段。

    因此,始终一次发送少于 1400 B。对于初学者。然后最重要的是,您需要处理不可靠传输带来的常见问题 - 正如 romkey 所提到的。一般来说,UDP 是视频等实时关键负载的正确选择(因为您需要对时间进行细粒度控制,而这在可靠传输中几乎是不可能的),但要做到这一点需要大量工作得很好。

    【讨论】:

    • “虽然UDP协议本身支持数据包的分片”——严格来说,UDP不执行用户发送的分片。 UDP 所做的只是在用户的发送中添加一个 UDP 标头并将其交给 IP。它在 IP 中发生分段(以及在接收器处,重新组装)。
    • 对,我已经有一段时间没有弄脏手了,所以我开始忘记细节了。更新中...
    • 好吧,我想我明白了!那么,我需要做的是尝试将发送消息分成 4 或 5 条不同的消息?或者我应该发送一个较小的图像,然后再发送一个较小的消息?
    • 说实话,这是你的决定。适合 MTU(大约 1460B)的图像将为您解决很多问题 :) 另一方面,如果您需要通过 UDP 发送更大的图像,那么您需要将图像切割成根据需要发送许多片段并发送这些片段。然后,您需要添加一个简单的框架协议来指示这是哪个片段,以及每个图像有多少。
    【解决方案2】:

    UDP - User Datagram Protocol - 被称为“不可靠”,因为它不保证交付。它一次传输每个数据包,如果未收到数据包,则不确认交付或尝试重新传输。您使用它传输的数据可能会也可能不会到达目的地,没有任何问题迹象。

    UDP 通常用于像 DNS 这样的低开销协议,其中请求适合单个数据包,并且只需重新传输请求就足够了,而对于像 NFS 这样的高性能协议,协议会跟踪已收到和未收到的内容,以及自己处理重传。

    接收器可能看不到您传输的内容的原因有很多,尤其是通过 Wifi,因为无线电噪声很容易损坏或丢失数据。

    如果您想使用 UDP 进行可靠通信,则需要构建自己的机制来重新传输未收到的数据。这很快就会变得复杂。除非你真的知道自己在做什么,否则最好还是坚持使用 TCP,它可以可靠地传输数据。

    【讨论】:

    • “您使用它传输的数据可能会或可能不会到达目的地,没有任何问题的迹象。”。是的,这是有道理的,但它不会是随机的吗?例如,在我的第一次尝试中,接收到的图像将是整个图像的 80%,但在第二次尝试中,将是 30%。换句话说,如果这是问题所在,我会不会每次都收到相同数量的像素?
    • 不一定。如果由于网络拥塞、wifi 干扰或类似问题而丢弃数据包,那么是的,它看起来是随机的。如果由于您耗尽了发送方或接收方的资源而丢弃了数据包,并且您的程序正在以一致的方式发送数据,那么您可能会看到丢失数据的模式。例如,如果您的程序传输的数据如此之快,以至于 ESP 或接收器(除非它是另一个 ESP,否则接收器不太可能)用完它的空间,那么您每次尝试时很可能会看到类似的结果。
    • 我认为@Tarmo 关于 MTU 的观点可能是导致您的问题的原因,但是如果您将数据分解为多次传输,您仍然不能指望 UDP 能够可靠地传递它们.
    猜你喜欢
    • 2017-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-08
    • 1970-01-01
    • 1970-01-01
    • 2021-04-14
    相关资源
    最近更新 更多