如何解决套接字读取通常在缓冲区不为空时返回-1
我正在尝试测试手机和Esp32(Arduino)之间的WiFi数据传输,当ESP32通过WiFi读取文件数据时,即使仍然有数据,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 times\n",filename,filesize,totallen,segment,i,j);
Serial.write(toClient);
curtime=millis();
sprintf(toClient,"time splashed %d ms,speed %d Bps\n",curtime-pretime,filesize*1000/(curtime-pretime));
Serial.write(toClient);
client.write(RETSUCCESS);
}
else
{
Serial.write("Unknow command\n");
}
}
}
// close the connection:
client.stop();
Serial.println("Client Disconnected.");
}
解决方法
当您调用 available() 并检查 > 0 时,您正在检查是否有一个或多个字符可供读取。如果只有一个角色到达,那将是真的。您阅读了一个字符,这很好,但随后您开始阅读更多内容,而没有停下来查看是否有更多可用字符。
TCP 不保证如果您将 100 个字符写入套接字,它们会同时到达。它们可以任意延迟到达任意“块”。唯一可以保证的是它们最终会按顺序到达(或者,如果由于网络问题而无法实现,则连接将失败。)
在没有阻塞读取功能的情况下(我不知道是否存在),您必须做一些类似于您正在做的事情。您必须一次读取一个字符并将其附加到缓冲区,从而优雅地处理获得 -1 的可能性(下一个字符尚未出现,或者连接中断)。通常,除非您刚刚使用了 available() 来确保 len 字符实际可用,否则您永远不想尝试在单个 read(buf,len) 中读取多个字符。如果您的缓冲区非常大,即使这样也可能失败。一次一个字符。
当 available() 返回 0 时调用 delay(1) 是一个合理的想法。在您尝试在读取缓冲区之前猜测诸如 delay(20) 之类的东西的地方,您正在掷骰子 - 没有保证 任何延迟量都将保证字节被传送。例子:也许一滴水落在芯片的天线上,直到水滴蒸发它才会工作。数据可能会延迟几分钟。
如果连接失败,我不知道 available() 的表现如何。您可能需要执行 read() 并返回 -1 以诊断连接失败。 Arduino 文档非常糟糕,因此您必须进行实验。
TCP 在具有线程、阻塞读取、select() 和其他工具来管理数据的平台上处理要简单得多。只有非阻塞读取会使事情变得更难,但确实如此。
在某些情况下,UDP 实际上要简单得多 - 在单个块中获取特定大小的消息有更多保证。但当然,整个消息可能会丢失或出现乱序。这是一种权衡。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。