现在我正使用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: Star
ting 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服务??