这次在使用W5500以太网硬件协议栈时,碰到了两个以后都需要注意的问题。在此记录下来。
一: W5500作为TCP Client端向TCP Server端发送数据时是有封装好的send(SOCKET s,const uint8 * buf,uint16 len)。
uint16 send(SOCKET s, const uint8 * buf, uint16 len)
{
uint8 status=0;
uint16 ret=0;
uint16 freesize=0;
if (len > getIINCHIP_TxMAX(s)) ret = getIINCHIP_TxMAX(s); /*Check size not to exceed MAX size*/
else ret = len;
printf("ret=%d\r\n",ret);
do
{
freesize = getSn_TX_FSR(s);
status = IINCHIP_READ(Sn_SR(s));
if ((status != SOCK_ESTABLISHED) && (status != SOCK_CLOSE_WAIT))
{
ret = 0;
break;
}
} while (freesize < ret);
send_data_processing(s, (uint8 *)buf, ret);
F12打进去这个函数以后可以看到有条if(len > getIINCHIP_TxMAX(s))判断语句。F12打进getIINCHIP_TxMAX(s)函数里,发现是返回SSIZE[S]。这个SSIZE[S]可以发现是在定义好的数组中,SSIZE[MAX_SOCK_NUM]中里。比如说,你使用TCP连接模式,这里的SOCKET s = 1。对应你就需要将SSIZE[1]改为大于你每次要发送的最大数据字节数。否则,在if(len > getIINCHIP_TxMAX(s))之后,ret = getIINCHIP_TxMAX(s),要发送的数据字节数就只能是数组里定义好的字节数。要发送的数据帧后的数据可能会丢失等情况出现。
继续往下看,这里还有个需要注意的地方。在do...while()语句中有条语句是freesize = getSn_TX_FSR(s)。这里是每次查看发送缓冲区里的内存。先回到最开始的初始化函数里有个socket_buf_init(txsize,rxsize)语句,它是用来初始化8个socket的收发缓冲区大小。F12打进去txsize,发现还是已经定义好的txsize[MAX_SOCK_NUM]数组。这里是默认的每个socket缓冲区是2KB。好了,可以回到freesize = getSn_TX_FSR(s)函数这里来。当W5500和服务器一直正常通信时,这个freesize>ret,不会一直循环在while()里面。然而,当SOCKET通信失败时则会将要发送的数据缓存在缓冲区内,并循环判断CHANNEL状态。当状态不处于建立连接或者不处于等待关闭中,说明通信断开,退出循环。函数后面会打印发送出错。或者当缓冲区的内存存了足够多的数据后,缓冲区剩余内存小于数据帧长度时,也会退出循环。
二:另一个问题就是添加心跳包功能。许多资料说明Set_Keep_Alive(socket c);打进去就是IINCHIP_WRITE(Sn_KPALVTR(s),0x02)。这里设置0x02,就是每隔10s发送一次心跳包给服务器端。然而在测试中发现,拔掉网线后再插上,并没有能重启网络,始终断开连接。查找资料后发现,要开启心跳包功能,必须要和服务器端进行一次双方通信后,才能正常使用心跳包功能。
添加心跳包可以实现断线后,N个周期(基于RTR和RCT)后,若仍没有收到对方的ACK信号,则会触发超时中断,并同时将Socket状态变为Closed。程序里只要加上监听Socket状态变为Closed之后就重新开发Socket监听/连接即可实现断线重连。
三:最近在调试代码时,遇到了首次烧写进去W5500 client模式下的代码进去,与服务器连接发送数据都没有问题。但是在断电后一晚上后,再重新上电。发现无论如何都和服务器连接不上了的问题。现在可能已经发现了问题所在。今天正在测试,若是成功测试出结果。后面会补上学习记录的。
在测试中发现了下面的情况。当W5500断电后,重新连接服务器时,一直连接不上。在把服务器打开后,终于发现了问题。原因是,在W5500断电之后,服务器端和W5500的TCP连接却是没有识别出已经断开了。所以,服务器端一直认为是连接正常,再次上电与服务器连接,就一直连接不上。(附上linux系统查询tcp连接语句查询:netstat -anp)所以,在使用W5500工程时,W5500客户端的IP固定的情况下,端口号Port不要固定。每次重新连接时,都使用一个新的port号。
case SOCK_CLOSED:
socket(SOCK_TCPC,Sn_MR_TCP,local_port++,Sn_MR_ND);
在修改了端口号不固定之后,这一周末一整天断电后,重新上电之后。成功连接上了服务器。并且,在服务器查询tcp连接状态,也发现断电之前的连接已经断开,重新上电连接后,与服务器使用了新的端口号进行了正常连接。