#sockets #arduino #wifi #esp32 #arduino-esp8266
#сокеты #arduino #wifi #esp32 #arduino-esp8266
Вопрос:
Я пытаюсь протестировать передачу данных Wi-Fi между мобильным телефоном и Esp32 (Arduino), когда ESP32 считывает данные файла через Wi-Fi, даже если в нем все еще есть данные, client.read() часто возвращает -1, я должен добавить другие условия, чтобы проверить, завершено чтение или нет.
Мой вопрос в том, почему так много неудачных чтений, любые идеи высоко ценятся.
void setup()
{
i=0;
Serial.begin(115200);
Serial.println("begin...");
// You can remove the password parameter if you want the AP to be open.
WiFi.softAP(ssid, password);
IPAddress myIP = WiFi.softAPIP();
Serial.print("AP IP address: ");
Serial.println(myIP);
server.begin();
Serial.println("Server started");
}
// the loop function runs over and over again until power down or reset
void loop()
{
WiFiClient client = server.available(); // listen for incoming clients
if(client) // if you get a client,
{
Serial.println("New Client."); // print a message out the serial port
Serial.println(client.remoteIP().toString());
while(client.connected()) // loop while the client's connected
{
while(client.available()>0) // if there's bytes to read from the client,
{
char c = client.read(); // read a byte, then
if(DOWNLOADFILE ==c){
pretime=millis();
uint8_t filename[32]={0};
uint8_t bFilesize[8];
long filesize;
int segment=0;
int remainder=0;
uint8_t data[512];
int len=0;
int totallen=0;
delay(50);
len=client.read(filename,32);
delay(50);
len=client.read(bFilesize,8);
filesize=BytesToLong(bFilesize);
segment=(int)filesize/512;
delay(50);
i=0; //succeed times
j=0; //fail times
////////////////////////////////////////////////////////////////////
//problem occures here, to many "-1" return value
// total read 24941639 bytes, succeed 49725 times, failed 278348 times
// if there were no read problems, it should only read 48,715 times and finish.
//But it total read 328,073 times, including 278,348 falied times, wasted too much time
while(((len=client.read(data,512))!=-1) || (totallen<filesize))
{
if(len>-1) {
totallen =len;
i ;
}
else{
j ;
}
}
///loop read end , too many times read fail//////////////////////////////////////////////////////////////////
sprintf(toClient, "nfile name %s,size %d, total read %d, segment %d, succeed %d times, failed %d timesn",filename,filesize,totallen,segment,i,j);
Serial.write(toClient);
curtime=millis();
sprintf(toClient, "time splashed %d ms, speed %d Bpsn", curtime-pretime, filesize*1000/(curtime-pretime));
Serial.write(toClient);
client.write(RETSUCCESS);
}
else
{
Serial.write("Unknow commandn");
}
}
}
// close the connection:
client.stop();
Serial.println("Client Disconnected.");
}
Ответ №1:
Когда вы вызываете available () и проверяете> 0, вы проверяете, есть ли один или несколько символов, доступных для чтения. Это будет верно, если прибыл только один символ. Вы читаете один символ, и это нормально, но затем вы начинаете читать дальше, не останавливаясь, чтобы посмотреть, есть ли еще доступные.
TCP не гарантирует, что если вы запишете 100 символов в сокет, все они поступят одновременно. Они могут поступать произвольными «порциями» с произвольными задержками. Все, что гарантировано, это то, что они в конечном итоге поступят по порядку (или, если это невозможно из-за проблем с сетью, соединение будет прервано.)
В отсутствие функции блокирующего чтения (я не знаю, существуют ли они) вы должны сделать что-то вроде того, что вы делаете. Вы должны читать по одному символу за раз и добавлять его в буфер, изящно передавая возможность получения -1 (следующего символа еще нет, или соединение разорвано). В общем, вы никогда не захотите пытаться прочитать несколько символов за одно чтение (buf, len), если вы только что не использовали available(), чтобы убедиться, что символы len действительно доступны. И даже это может привести к сбою, если ваши буферы действительно большие. Придерживайтесь одного символа за раз.
Разумно вызывать delay(1), когда функция available() возвращает 0. В тех местах, где вы пытаетесь угадать что-то вроде delay (20) перед чтением буфера, вы бросаете кости — нет никаких обещаний, что любая задержка гарантирует доставку байтов. Пример: возможно, капля воды упала на антенну чипа, и она не будет работать, пока капля не испарится. Данные могут задерживаться на несколько минут.
Я не знаю, как ведет себя функция available() в случае сбоя соединения. Возможно, вам придется выполнить read() и получить обратно -1, чтобы диагностировать неудачное соединение. Документация Arduino абсолютно ужасна, поэтому вам придется поэкспериментировать.
TCP намного проще обрабатывать на платформах, которые имеют потоки, блокирующие чтение, select() и другие инструменты для управления данными. Наличие только неблокирующего чтения усложняет задачу, но это так.
В некоторых ситуациях UDP на самом деле намного проще — есть больше гарантий получения сообщений определенного размера в одном блоке. Но, конечно, целые сообщения могут пропадать или отображаться не по порядку. Это компромисс.