前面我们已经学习了TCP的所有发送、接收和各种回调函数。本文将介绍最后一部分,TCP的轮询机制。
在前面TCP发送Hello World的实例中,我们是在main函数的while循环中每隔1s调用一次数据发送函数。本文的实例将利用轮询机制完成同样的功能。
SDK程序设计
本文根据TCP client模式下发送hello world的程序改编(server模式改动也类似)。主要差别在user_udp.c文件中, 其余文件代码基本相同(main.c的while循环中无需调用send_data函数发送数据)。
#include "user_tcp.h"
#define SEND_SIZE 12
static struct tcp_pcb *connected_pcb = NULL;
int tcp_poll_cnt = 0;
char sendBuffer[12]="Hello World!";
//--------------------------------------------------
// TCP轮询的回调函数
//--------------------------------------------------
err_t tcp_poll_callback(void * arg, struct tcp_pcb * tpcb)
{
tcp_poll_cnt++; //统计发送数据的次数
xil_printf("poll int:%d\r\n", tcp_poll_cnt);
send_data();
return ERR_OK;
}
//--------------------------------------------------
// TCP连接成功的回调函数
//--------------------------------------------------
err_t tcp_connected_callback(void *arg, struct tcp_pcb *tpcb, err_t err)
{
xil_printf("txperf: Connected to iperf server\r\n");
connected_pcb = tpcb; //存储连接的TCP状态
tcp_nagle_disable(connected_pcb);
tcp_arg(tpcb, NULL); //指定应该传递回调函数的参数
//设置轮询回调函数tcp_sent_callback
tcp_poll(connected_pcb, tcp_poll_callback, 2);
xil_printf("Connect Success.\r\n");
return ERR_OK;
}
//--------------------------------------------------
// TCP PCB初始化函数
//--------------------------------------------------
int tcp_send_init()
{
struct tcp_pcb *pcb;
struct ip_addr ipaddr;
err_t err;
u16_t port;
//创建新的TCP PCB
pcb = tcp_new();
if (!pcb) {
xil_printf("txperf: Error creating PCB. Out of Memory\r\n");
return -1;
}
IP4_ADDR(&ipaddr, 192, 168, 1, 100); //服务器的IP地址
port = 7; //服务器的默认端口
//连接主机,连接建立后调用回调函数tcp_connected_callback
err = tcp_connect(pcb, &ipaddr, port, tcp_connected_callback);
if (err != ERR_OK) {
xil_printf("txperf: tcp_connect returned error: %d\r\n", err);
return err;
}
xil_printf("%d\r\n",err);
return 0;
}
//--------------------------------------------------
// TCP数据发送函数
//--------------------------------------------------
void send_data(void)
{
err_t err;
struct tcp_pcb *tpcb = connected_pcb;
if (!connected_pcb)
return;
err = tcp_write(tpcb, sendBuffer, SEND_SIZE, 3);
if (err != ERR_OK) {
xil_printf("txperf: Error on tcp_write: %d\r\n", err);
connected_pcb = NULL;
return;
}
err = tcp_output(tpcb);
if (err != ERR_OK) {
xil_printf("txperf: Error on tcp_output: %d\r\n",err);
return;
}
}
在连接成功的回调函数tcp_connected_callback中,使用tcp_poll函数绑定TCP的轮询回调函数tcp_poll_callback。当连接处于空闲状态时(即没有发送或接收数据),lwIP将周期性的调用轮询回调函数。
tcp_toll指定轮询应用程序时应调用的回调函数和轮询间隔。TCP有一个粗略的计时器,大概一秒钟发出两次信号,轮询间隔时间和此有关。此处设置为2,则表示应用程序大约每(2/2=)1秒轮询一次。本例在轮询回调函数中发送数据。
这种机制类似看门狗定时器,以解决长时间处于空闲状态的连接;也可以作为一种等待内存变为可用状态的方法。比如当内存不可用导致tcp_write的调用失败时,应用程序可以在连接空闲了一段时间后,使用轮询功能再次调用tcp_write。
测试结果如下,串口信息中可看到进入轮询回调函数的次数:
总结
止此,lwIP中所有与UDP、TCP相关的函数即使用方法都介绍完毕,且给出了实例的形式。希望对各位有帮助。
---------------------