乐鑫技术交流
直播中

王敏

7年用户 1450经验值
私信 关注
[问答]

使用Lwip非阻塞的tcp socket时,能同时运行tcp socket和https服务吗?

现在我正使用lwip的非阻塞socket作为tcp通信手段,然后在此过程中,进行https的ota操作,然后发现出现socket read fail问题 并且https也无法使用,若将当前socket关闭,则可以正常进行https升级,请问下有什么好的方法能解决此问题?(当前是wifi sta模式)
另外发现若采用以太网模式(不使用wifi,则https可以正常OTA,但是tcp还是会提示失败)

使用wifi log如下(tcp read 返回-9错误):
[0;32mI (46199) HXJ_OTA: Starting OTA example...[0m
[0;32mI (46199) HXJ_OTA: config.URL:https://file.hxjiot.com/firmware/C849A7 ... 18A870.bin[0m
[0;32mI (46209) HXJ_OTA: Running partition type 0 subtype 16 (offset 0x00080000)[0m
[0;32mI (46229) HXJ_TCPCLIENT: tcp错误errono=9[0m
[0;32mI (46229) HXJ_TCPCLIENT: tcp read failed
[0m
[0;31mE (46239) esp-tls: mbedtls_ssl_setup returned -0x7f00

[0m
[0;31mE (46249) esp-tls: Failed to open new connection[0m
[0;31mE (46249) TRANS_SSL: Failed to open a new connection[0m
[0;31mE (46249) HTTP_CLIENT: Connection failed, sock < 0[0m
[0;32mI (46259) HXJ_OTA: HTTP_EVENT_DISCONNECTED[0m
[0;31mE (46259) HXJ_OTA: Failed to open HTTP connection: ESP_ERR_HTTP_CONNECT[0m
[0;31mE (46269) HXJ_OTA: Firmware Upgrades Failed[0m
[/code]


使用以太网 log如下 (一开始进行https,则tcp read马上返回 -9错误)
Code: Select all
[0;32mI (17869) HXJ_OTA: Starting OTA example...[0m[0;32mI (17869) HXJ_OTA: config.URL:https://file.hxjiot.com/firmware/C849A7A10470000151FB14E91918A870.bin[0m[0;32mI (17879) HXJ_OTA: Running partition type 0 subtype 16 (offset 0x00080000)[0m[0;32mI (17899) HXJ_TCPCLIENT: tcp错误errono=9[0m[0;32mI (17899) HXJ_TCPCLIENT: tcp read failed[0m[0;32mI (18969) HXJ_OTA: HTTP_EVENT_ON_CONNECTED[0m[0;32mI (18989) HXJ_OTA: HTTP_EVENT_ON_HEADER, key=Server, value=Tengine[0m[0;32mI (18989) HXJ_OTA: HTTP_EVENT_ON_HEADER, key=Content-Type, value=application/octet-stream[0m[0;32mI (18989) HXJ_OTA: HTTP_EVENT_ON_HEADER, key=Content-Length, value=1015536[0m[0;32mI (18999) HXJ_OTA: HTTP_EVENT_ON_HEADER, key=Connection, value=keep-alive[0m[0;32mI (19009) HXJ_OTA: HTTP_EVENT_ON_HEADER, key=Date, value=Fri, 11 Jan 2019 04:21:14 GMT[0m[0;32mI (19009) HXJ_OTA: HTTP_EVENT_ON_HEADER, key=Accept-Ranges, value=bytes[0m[0;32mI (19019) HXJ_OTA: HTTP_EVENT_ON_HEADER, key=Access-Control-Allow-Origin, value=*[0m[0;32mI (19029) HXJ_OTA: HTTP_EVENT_ON_HEADER, key=Access-Control-Expose-Headers, value=X-Log, X-Reqid[0m[0;32mI (19039) HXJ_OTA: HTTP_EVENT_ON_HEADER, key=Access-Control-Max-Age, value=2592000[0m[0;32mI (19049) HXJ_OTA: HTTP_EVENT_ON_HEADER, key=Cache-Control, value=public, max-age=31536000[0m[0;32mI (19059) HXJ_OTA: HTTP_EVENT_ON_HEADER, key=Content-Disposition, value=inline; filename="C849A7A10470000151FB14E91918A870.bin"; filename*=utf-8' 'C849A7A10470000151FB14E91918A870.bin[0m[0;32mI (19069) HXJ_OTA: HTTP_EVENT_ON_HEADER, key=Content-Transfer-Encoding, value=binary[0m[0;32mI (19079) HXJ_OTA: HTTP_EVENT_ON_HEADER, key=Etag, value="F[0m[0;32mI (19089) HXJ_OTA: HTTP_EVENT_ON_HEADER, key=Last-Modified, value=Wed, 09 Jan 2019 08:47:51 GMT[0m[0;32mI (19099) HXJ_OTA: HTTP_EVENT_ON_HEADER, key=X-Log, value=redis.g/404;mc.g/404;redis.g;rs40_shard.sel:5;rwro.get:5;RS.dbs:5;RS:5;redis.s;1s.gh:27;PFDS:28;IO:37[0m[0;32mI (19109) HXJ_OTA: HTTP_EVENT_ON_HEADER, key=X-M-Log, value=QNM:xs459;SRCPROXY:xs485;SRC:37;SRCPROXY:37;QNM3:40[0m[0;32mI (19119) HXJ_OTA: HTTP_EVENT_ON_HEADER, key=X-M-Reqid, value=PSoAAFphsNFxsHgV[0m[0;32mI (19129) HXJ_OTA: HTTP_EVENT_ON_HEADER, key=X-Qiniu-Zone, value=0[0m[0;32mI (19139) HXJ_OTA: HTTP_EVENT_ON_HEADER, key=X-Qnm-Cache, value=Miss[0m[0;32mI (19149) HXJ_OTA: HTTP_EVENT_ON_HEADER, key=X-Reqid, value=rVIAAMnh3tFxsHgV[0m[0;32mI (19149) HXJ_OTA: HTTP_EVENT_ON_HEADER, key=X-Svr, value=IO[0m[0;32mI (19159) HXJ_OTA: HTTP_EVENT_ON_HEADER, key=Ali-Swift-Global-Savetime, value=1547180474[0m[0;32mI (19169) HXJ_OTA: HTTP_EVENT_ON_HEADER, key=Via, value=cache35.l2su18-2[184,200-0,M], cache36.l2su18-2[186,0], vcache5.cn627[0,200-0,H], vcache7.cn627[1,0][0m[0;32mI (19179) HXJ_OTA: HTTP_EVENT_ON_HEADER, key=Age, value=10843[0m[0;32mI (19189) HXJ_OTA: HTTP_EVENT_ON_HEADER, key=ache, value=HIT TCP_MEM_HIT dirn:12:155996968[0m[0;32mI (19199) HXJ_OTA: HTTP_EVENT_ON_HEADER, key=X-Swift-SaveTime, value=Fri, 11 Jan 2019 04:21:15 GMT[0m[0;32mI (19209) HXJ_OTA: HTTP_EVENT_ON_HEADER, key=X-Swift-CacheTime, value=2592000[0m[0;32mI (19219) HXJ_OTA: HTTP_EVENT_ON_HEADER, key=Timing-Allow-Origin, value=*[0m[0;32mI (19219) HXJ_OTA: HTTP_EVENT_ON_HEADER, key=EagleId, value=7909f64715471913177701228e[0m[0;32mI (19229) HXJ_OTA: HTTP_EVENT_ON_DATA, len=195[0m[0;32mI (19239) HXJ_OTA: Starting OTA...[0m[0;32mI (19239) HXJ_OTA: Writing to partition subtype 17 at offset 0x240000[0m[0;32mI (20699) HXJ_OTA: esp_ota_begin succeeded[0m[0;32mI (20699) HXJ_OTA: Please Wait. This may take time[0m[0;32mI (20709) HXJ_OTA: HTTP_EVENT_ON_DATA, len=317[0m[0;32mI (20709) HXJ_OTA: Written image length 512[0m[0;32mI (20709) HXJ_OTA: HTTP_EVENT_ON_DATA, len=512[0m[0;32mI (20719) HXJ_OTA: Written image length 1024[0m[0;32mI (20719) HXJ_OTA: HTTP_EVENT_ON_DATA, len=512[0m[0;32mI (20729) HXJ_OTA: Written image length 1536[0m[0;32mI (20729) HXJ_OTA: HTTP_EVENT_ON_DATA, len=59[0m[0;32mI (20739) HXJ_OTA: HTTP_EVENT_ON_DATA, len=453[0m

非阻塞tcp实现代码如下:Code: Select all
/*============================================================================== * Function:        new_tcp_read() * Description:     非阻塞tcp读取 * Input:           none * Return:          none * Others:          none *============================================================================*/static int new_tcp_read(int tcp_fd, unsigned char* buf, unsigned short len){    int ret = -1;    if(buf == NULL)    {        return -1;    }        /*TCP读取数据需要判断错误码*/    ret = (int)(recv(tcp_fd, buf, len, MSG_DONTWAIT));    if(ret <= 0)    {                    if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)        {            return 0;//OK        }        else        {                ESP_LOGI(TAG,"tcp错误errono=%d",errno);            return -1;        }    }            return ret;}/*============================================================================== * Function:        new_tcp_state() * Description:     非阻塞tcp设置参数 * Input:           none * Return:          none * Others:          none *============================================================================*/static int new_tcp_state(int sock){    int errcode = 0;    int tcp_fd = sock;    if(tcp_fd < 0) {        return -1;    }  #if 1      fd_set rset, wset;    int ready_n;    FD_ZERO(&rset);    FD_SET(tcp_fd, &rset);    wset = rset;    struct timeval timeout;    timeout.tv_sec = 3;    timeout.tv_usec = 0;        /*使用select机制判断tcp连接状态*/    ready_n = select(tcp_fd + 1, &rset, &wset, NULL, &timeout);    if(0 == ready_n)    {        ESP_LOGI(TAG,"select time outn");        errcode = -1;    }    else if(ready_n < 0)    {        ESP_LOGI(TAG,"select errorn");        errcode = -1;    }    else    {    //    ESP_LOGI(TAG,"FD_ISSET(tcp_fd, &rset):%dn FD_ISSET(tcp_fd, &wset):%dn",//                        (int)FD_ISSET(tcp_fd, &rset) , (int)FD_ISSET(tcp_fd, &wset));         // test in linux environment,kernel version 3.5.0-23-generic         // tcp server do not send msg to client after tcp connecting        int ret;        socklen_t len = sizeof(int);        if(0 != getsockopt (tcp_fd, SOL_SOCKET, SO_ERROR, &ret, (socklen_t*)&len))        {            ESP_LOGI(TAG,"getsocketopt failedrn");            errcode = -1;        }               // ESP_LOGI(TAG,"getsocketopt ret=%d errno %drn",ret, errno);        if(0 != ret)        {                ESP_LOGI(TAG,"getsocketopt ret=%d errno %drn",ret, errno);            errcode = -1;        }    }#endif        int ret;        socklen_t len = sizeof(int);        if(0 != getsockopt (tcp_fd, SOL_SOCKET, SO_ERROR, &ret, (socklen_t*)&len))        {                ESP_LOGI(TAG,"getsocketopt failedrn");                errcode = -1;        }        // ESP_LOGI(TAG,"getsocketopt ret=%d errno %drn",ret, errno);        if(0 != ret)        {                ESP_LOGI(TAG,"getsocketopt ret=%d errno %drn",ret, errno);                errcode = -1;        }    return errcode;}/*============================================================================== * Function:        new_tcp_send() * Description:     非阻塞tcp发送 * Input:           none * Return:          none * Others:          none *============================================================================*/int new_tcp_send(int tcp_fd, const unsigned char* buf, unsigned short len){    int ret = -1;    if(buf == NULL)    {        return -1;    }        /*TCP发送数据需要判断错误码*/    ret = (int)(send(tcp_fd, buf, len, MSG_DONTWAIT));    if(ret < 0)    {        if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)        {            return 0;        }        else        {            return -1;        }    }        ESP_LOGI(TAG,"new_tcp_send=%d",ret);    return ret;}static int new_tcp_connect(in_addr_t srcip,const char* dst, unsigned short port){        struct sockaddr_in servaddr;        int tcp_fd;        int flags;        int reuse;        if(NULL == dst)        {                return -1;        }        tcp_fd = socket(AF_INET, SOCK_STREAM, 0);        if(tcp_fd < 0)        {                ESP_LOGI(TAG,"creat socket tcp_fd failedn");                return -1;        }        /*设置非阻塞模式*/        flags = fcntl(tcp_fd, F_GETFL, 0);        if(flags < 0 || fcntl(tcp_fd, F_SETFL, flags | O_NONBLOCK) < 0)        {                ESP_LOGI(TAG,"fcntl: %sn", strerror(errno));                close(tcp_fd);                return -1;        }                reuse = 1;                if(setsockopt(tcp_fd, SOL_SOCKET, SO_REUSEADDR,                                        (const char *) &reuse, sizeof( reuse ) ) != 0 )        {                close(tcp_fd);                ESP_LOGI(TAG,"set SO_REUSEADDR failedn");                return -1;        }                memset(&servaddr, 0, sizeof(struct sockaddr_in));        servaddr.sin_family = AF_INET;        servaddr.sin_addr.s_addr = inet_addr(dst);        servaddr.sin_port = htons(port);                struct sockaddr_in src;        memset(&src,0,sizeof(struct sockaddr_in));        src.sin_addr.s_addr = srcip;//使用sta的 ip        src.sin_family = AF_INET;        src.sin_port=htons(10000);                        //destAddr.sin_port = htons(PORT);                //绑定一下 ip        //bind(tcp_fd,&src,sizeof(struct sockaddr));                if(connect(tcp_fd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr_in)) == 0)        {                return tcp_fd;        }        else        {                if(errno == EINPROGRESS)                {                        ESP_LOGI(TAG,"tcp conncet noblockn");                        return tcp_fd;                }                else                {                        close(tcp_fd);                        return -1;                }        }}
整体逻辑如下:Code: Select all
tcp_fd = new_tcp_connect( (in_addr_t)sta_ip.ip.addr,Host, Port);//recv_len为1024if(new_tcp_state(tcp_fd)!= 0){        ESP_LOGI(TAG,"tcp not connectn");        break; //  continue;}else{        ESP_LOGI(TAG,"tcp connect successufllyn");        tcp_connect_flag = 1;}while(1){        //省略发送等其他逻辑        recv_len = new_tcp_read(tcp_fd, tcp_reveive_buffer, tcp_max_size-1);        if(recv_len > 0)        {                ESP_LOGI(TAG,"recv data:%s,length:%dn", tcp_reveive_buffer, recv_len);                InterNet_Receive((char *)&tcp_reveive_buffer,recv_len);                clilenttcp_get_answer=1;        }        else if(recv_len == 0)        {           // ESP_LOGI(TAG,"recv no datan");          //  continue;        }        else        {                ESP_LOGI(TAG,"tcp read failedn");                break;        }        vTaskDelay(30 / portTICK_PERIOD_MS);//每30ms读取1K数据}//TCP失败到此                    
请问下有没有方法能同时运行tcp socket和https服务??

回帖(1)

张涛

2024-6-7 17:46:44
在LwIP中,非阻塞TCP socket和HTTPS服务可以同时运行,但需要确保正确地管理它们之间的资源和调度。从您提供的信息来看,您在WiFi STA模式下遇到了socket read失败的问题,而在以太网模式下HTTPS OTA可以正常工作。以下是一些建议来解决这个问题:

1. **确保线程调度**:在多任务环境中,确保LwIP的任务调度器(例如`tcpip_thread`)能够正确运行。这通常意味着您需要在应用程序中创建一个单独的线程来处理LwIP的任务。

2. **检查内存分配**:确保您的系统有足够的堆内存来处理TCP连接和HTTPS请求。如果内存不足,可能导致socket操作失败。

3. **优化超时设置**:检查您的LwIP配置中的超时设置,确保它们适合您的网络环境。过短的超时可能导致socket操作失败。

4. **错误处理**:在您的代码中添加更详细的错误处理和日志记录,以便更好地了解问题所在。例如,当socket read失败时,记录错误代码和相关上下文信息。

5. **避免阻塞操作**:确保在处理TCP socket和HTTPS请求时,不要使用阻塞操作。这可能导致任务调度器无法正常工作,从而影响整个系统的稳定性。

6. **调整优先级**:如果可能的话,尝试调整LwIP任务和HTTPS任务的优先级,以确保它们能够合理地共享CPU资源。

7. **考虑使用其他库**:如果您发现LwIP在非阻塞模式下的性能不佳,可以考虑使用其他支持非阻塞操作的网络库,例如mbedTLS(用于HTTPS)和lwIP的替代品。

8. **更新固件和库**:确保您的设备固件和使用的库(如LwIP和mbedTLS)是最新版本,以获得最佳的性能和稳定性。

通过以上建议,您应该能够找到并解决在WiFi STA模式下遇到的socket read失败问题。同时,确保在以太网模式下也进行相应的优化,以提高整个系统的稳定性和性能。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分