套接字读取通常在缓冲区不为空时返回-1

如何解决套接字读取通常在缓冲区不为空时返回-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 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-