量产的产品偶尔会出现网络正常,但ntp同步失败的现象,正常情况下, 有多台ntp服务器提供服务,即使一台服务器没有响应,不可能三台同时都没有响应。经过检查后发现,ntp软件包里多次调用了sendto()函数,每次传入不同的to参数
/* Create a UDP socket. */
sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sockfd < 0)
{
LOG_E("Create socket failed");
return 0;
}
if (host_name)
{
/* access the incoming host_name server */
if (sendto_ntp_server(sockfd, host_name, serv_addr) >= 0)
{
server_num = 1;
}
}
else
{
/* use the static default NTP server */
for (i = 0; i < NTP_SERVER_NUM; i++)
{
if (host_name_buf[i] == RT_NULL || strlen(host_name_buf[i]) == 0)
continue;
if (sendto_ntp_server(sockfd, host_name_buf[i], &serv_addr[server_num]) >= 0)
{
server_num ++;
}
}
}
这符合POSIX规范,也就是无连接的UDP,但是AT组件里无法处理这种情况,在at组件里,UDP在发送数据前会检查socket是否连接,没有连接就会先去调用at_connect()函数,如果已经是连接状态,就直接发送数据,并不会做其他处理。代码如下:
case AT_SOCKET_UDP:
if (to && sock->state == AT_SOCKET_OPEN)
{
ip_addr_t remote_addr;
uint16_t remote_port = 0;
char ipstr[16] = { 0 };
socketaddr_to_ipaddr_port(to, &remote_addr, &remote_port);
ipaddr_to_ipstr(to, ipstr);
if (sock->ops->at_connect(sock, ipstr, remote_port, sock->type, RT_TRUE) < 0)
{
result = -1;
goto __exit;
}
sock->state = AT_SOCKET_CONNECT;
}
if ((len = sock->ops->at_send(sock, (char *) data, size, sock->type)) < 0)
{
result = -1;
goto __exit;
}
break;
default:
LOG_E("Socket (%d) type %d is not support.", socket, sock->type);
result = -1;
goto __exit;
}
所以导致ntp失败的问题也就显而易见了,每次ntp软件包试图向多台服务器发送数据时,数据实际只会发往第一台服务器,如果这台服务器不响应,同步就失败了。