CH395 tcp客户端 热拔插
CH395做tcp客户端,实现网线拔掉后tcp断开,网线插上后tcp连接。
目前提供三种思路:
芯片测试版本:0x49,测试工具:TCPIPDebug做服务器
1.第一种思路
(1)代码:(在CH395的tcp_client例程的超时终端和PHY_Change中断中加上下面的代码即可)
1 u8 sock_sta[2]; 2 u8 i ; 3 if(init_status & GINT_STAT_PHY_CHANGE) /* 产生PHY改变中断*/ 4 { 5 CH395CMDGetSocketStatus(0,sock_sta); /*查询socket状态*/ 6 printf("SOCK-sta:%x %x\r\n",sock_sta[0],sock_sta[1]); 7 8 if(sock_sta[0] == 0x05 && sock_sta[1] == 0x04) /*socket已打开且tcp已建立*/ 9 { 10 i = CH395CloseSocket(0); 11 mStopIfError(i); 12 } 13 } 14 15 16 if(sock_int_socket & SINT_STAT_TIM_OUT) /* 超时中断 */ 17 { 18 printf("超时中断 \n"); 19 i = CH395OpenSocket(sockindex); /* 打开socket 0 */ 20 mStopIfError(i); /* 检查是否成功 */ 21 i = CH395TCPConnect(sockindex); 22 mStopIfError(i); 23 }
(2)原理:
①拔插网线都会产生相同的PHY_Change中断,如何判断此时是拔网线的动作还是插网线的动作?在tcp模式下,可以通过查socket状态来区别(当然也可以直接通过查询phy的协商状态来判断),如上程序,当网线插上时,由于是tcp客户端模式,所以395会发送SYN握手,此时socket的状态为SYN发送态(上述代码没写,这个不需要),当tcp建立完成后,socket的状态改为TCP连接建立态;当tcp建立成功后,此时我们拔掉网线,进入phy_change中断,查到socket的状态为连接态,执行关闭socket的函数。(PS:关于tcp的连接状态参考手册5.22章节)
②由于执行了关闭socket的函数,所以395会发送FIN挥手包以此希望断开此次tcp连接,但是由于此时网线被拔掉,导致FIN包不能正常发包。因此,此时如果我们插上网线,可以看到395会立马发出之前想要发但没能发出去的FIN包,此时服务端并不会执行正常的挥手,而是直接发送RST包复位到之前的tcp连接,之后395检测到tcp断开异常,因此会产生超时中断,我们在超时中断中重新打开socket和执行tcp连接函数即可实现功能。
注:抓包如下,192.168.1.112是395的ip,192.168.1.100是PC服务器的ip
2.第二种思路,不采用超时中断的方式,全在放在phy_change中断中处理。但由于395的机制,一旦进入超时中断或断开中断,都会默认关闭该socket,所以为了以防意外情况导致tcp连接断掉,一般都建议在这两个中断里加上打开socket的操作以保证异常发生后还能继续实现tcp通信,所以第二种方式不做推荐,在此就不多赘述。
3.第三种思路,借助keeplive功能实现。代码如下,根据手册要求,tcp客户端模式下需要在tcp连接成功后开启此功能,keeplive的空闲时间为5秒、超时时间为3秒和重试次数为200(参考手册5.56~5.59章节)
1 if(sock_int_socket & SINT_STAT_CONNECT) /* 连接中断,仅在TCP模式下有效*/ 2 { 3 printf("连接中断 \n"); 4 CH395SetKeepLive(sockindex,1); /*打开KEEPALIVE保活定时器*/ 5 } 6 7 8 if(sock_int_socket & SINT_STAT_TIM_OUT) /* 超时中断 */ 9 { 10 printf("超时中断 \n"); 11 i = CH395OpenSocket(sockindex); /* 打开socket 0 */ 12 mStopIfError(i);/* 检查是否成功 */ 13 i = CH395TCPConnect(sockindex); 14 mStopIfError(i); 15 }
原理:
tcp连接建立成功后,由于实际应用中,可能并不是时时刻刻都有数据传输,此时一般会开启keeplive功能来实现保活。如下,tcp连接建立后,当20ms无数据传输时,395会发送keep-alive包,服务器收到会回复相应的ack包。
此时拔掉网线,当网线再次插上,395会尝试发送keeplive包,此时服务器会直接将将连接RST掉,导致进入超时中断,从而重新打开open和建立tcp连接
总结:推荐第一种方式,如有更好的方法可以评论交流