使用Lwip非阻塞的tcp socket时, 进行https的ota升级,会失败

xuanzihao
Posts: 6
Joined: Thu Dec 06, 2018 3:59 am

使用Lwip非阻塞的tcp socket时, 进行https的ota升级,会失败

Postby xuanzihao » Fri Jan 11, 2019 7:30 am

Hello,
现在我正使用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 out\n");
        errcode = -1;
    }
    else if(ready_n < 0)
    {
        ESP_LOGI(TAG,"select error\n");
        errcode = -1;
    }
    else
    {
    //    ESP_LOGI(TAG,"FD_ISSET(tcp_fd, &rset):%d\n FD_ISSET(tcp_fd, &wset):%d\n",
//                        (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 failed\r\n");
            errcode = -1;
        }
       	// ESP_LOGI(TAG,"getsocketopt ret=%d errno %d\r\n",ret, errno);
        if(0 != ret)
        {
        	ESP_LOGI(TAG,"getsocketopt ret=%d errno %d\r\n",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 failed\r\n");
		errcode = -1;
	}
	// ESP_LOGI(TAG,"getsocketopt ret=%d errno %d\r\n",ret, errno);
	if(0 != ret)
	{
		ESP_LOGI(TAG,"getsocketopt ret=%d errno %d\r\n",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 failed\n");
		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: %s\n", 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 failed\n");
		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 noblock\n");
			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为1024
if(new_tcp_state(tcp_fd)!= 0)
{
	ESP_LOGI(TAG,"tcp not connect\n");
	break;
 //  continue;
}
else
{
	ESP_LOGI(TAG,"tcp connect successuflly\n");
	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:%d\n", 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 data\n");
	  //  continue;
	}
	else
	{
		ESP_LOGI(TAG,"tcp read failed\n");
		break;
	}
	vTaskDelay(30 / portTICK_PERIOD_MS);//每30ms读取1K数据
}
//TCP失败到此
	            
请问下有没有方法能同时运行tcp socket和https服务??

谢谢!!!!!!

Who is online

Users browsing this forum: No registered users and 2 guests