写这篇文章是因为 ESP8266 SDK 包自带的 STNP 经常同步时间失败,只能寻找新的办法了。通过分析发现自己编写TCP通信代码就能拿到时间,下面我们来讲述下其原理:
很多http网页如果请求失败会带时间戳返回,可以利用这个原理来提取系统时间:
我下面的例子就是简单的获取时分秒,年月日里就月份比较难获取而已,有兴趣自己弄下。
void ICACHE_FLASH_ATTR espconn_connect_cb(void *arg) {
char a;
os_printf("\n*********** espconn_connect_cb ***********\n");
if (tcp_client.state == ESPCONN_CONNECT) {
os_printf("send to server...\n");
a = '1'; //发任意数据就行了
espconn_sent(&tcp_client, &a, 1);
}
}
//espconn_recv_cb(),len=295
//HTTP/1.1 400 Bad Request
//Server: nginx
//Date: Wed, 08 May 2019 02:58:25 GMT
//Content-Type: text/html
//Content-Length: 150
//Connection: close
//
//<html>
//<head><title>400 Bad Request</title></head>
//<body>
//<center><h1>400 Bad Request</h1></center>
//<hr><center>nginx</center>
//</body>
//</html>
void ICACHE_FLASH_ATTR espconn_recv_cb(void *arg, char *pdata,
unsigned short len) {
char *pdst;
int shi, fen, miao;
if (len > 100)
pdata[100] = '\0';
else
pdata[len] = '\0';
os_printf("\nespconn_recv_cb(),len=%d\n%s\n", len, pdata);
if (isSyncSTNP == 0) {
if (os_memcmp(pdata, "HTTP/1.1 400 Bad Request",
sizeof("HTTP/1.1 400 Bad Request") - 1) == 0) {
pdst = os_strstr(pdata, " GMT");
if (pdst != NULL) {
os_printf(" GMT pos=%d\n"
"", pdst - pdata);
pdst -= 8; //退8个字节
if (sscanf(pdst, "%d:%d:%d", &shi, &fen, &miao) == 3) {
shi += 8;
shi %= 24;
os_printf("******* %d:%d:%d ********\n", shi, fen, miao);
}
}
}
}
}
/**参考链接 https://www.cnblogs.com/imliubo/p/10090857.html
* TCP Client初始化函数
* @remote_ip 要连接的TCP Server IP地址
* @local_ip ESP8266 IP地址
* @remote_port 要连接的TCP Server端口号
*/
void ICACHE_FLASH_ATTR
tcp_client_init(uint8 *remote_ip, struct ip_addr *local_ip, int remote_port) {
uint32 server_ip = ipaddr_addr(remote_ip);
os_printf("tcp client connect to tcp server...\r\n");
tcp_client.proto.tcp = (esp_tcp *) os_zalloc(sizeof(esp_tcp));
tcp_client.type = ESPCONN_TCP;
os_memcpy(tcp_client.proto.tcp->remote_ip, &server_ip, 4); //设置要连接的Server IP地址
tcp_client.proto.tcp->remote_port = remote_port; //设置要连接的Server 端口号
os_memcpy(tcp_client.proto.tcp->local_ip, local_ip, 4); //设置本地IP地址
tcp_client.proto.tcp->local_port = espconn_port(); //设置本地端口号
espconn_regist_connectcb(&tcp_client, espconn_connect_cb); //注册连接成功回调函数
espconn_regist_reconcb(&tcp_client, espconn_reconnect_cb); //注册断连重新连接回调函数
espconn_regist_sentcb(&tcp_client, espconn_sent_cb);
espconn_regist_recvcb(&tcp_client, espconn_recv_cb);
espconn_regist_disconcb(&tcp_client, espconn_discon_cb);
espconn_connect(&tcp_client); //Client连接Server
}
我们来重点看看怎么调用的:
#define TCP_SERVER_IP "139.199.7.215"
#define TCP_SERVER_PORT 80
struct espconn tcp_client;
void ICACHE_FLASH_ATTR
user_init(void) {
.....
espconn_init();
wifi_set_event_handler_cb(event_handler);
.....
}
void event_handler(System_Event_t *event) {
switch (event->event_id) {
case EVENT_STAMODE_GOT_IP:
struct ip_info local_ip;
wifi_get_ip_info(STATION_IF, &local_ip);
//TCP Client初始化,Client与Server只能二选一
tcp_client_init(TCP_SERVER_IP, &local_ip.ip, TCP_SERVER_PORT);
break;
...
}
}
这样写确实是可以最快时间校时,如果IP变了就不行啦~