C:\Users\dell\STM32Cube\Repository\STM32Cube_FW_F4_V1.25.2\Projects\STM324xG_EVAL\Applications\LwIP\LwIP_TCP_Echo_Server\Src
主要代码:
extern void tcp_echoserver_init(void);
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_LWIP_Init();
/* USER CODE BEGIN 2 */
tcp_echoserver_init();
printf("system is start!\r\n");
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
MX_LWIP_Process();
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
static struct tcp_pcb *tcp_echoserver_pcb;
/* ECHO protocol states */
enum tcp_echoserver_states
{
ES_NONE = 0,
ES_ACCEPTED,
ES_RECEIVED,
ES_CLOSING
};
/* structure for maintaing connection infos to be passed as argument
to LwIP callbacks*/
struct tcp_echoserver_struct
{
u8_t state; /* current connection state */
u8_t retries;
struct tcp_pcb *pcb; /* pointer on the current tcp_pcb */
struct pbuf *p; /* pointer on the received/to be transmitted pbuf */
};
void tcp_echoserver_init(void);
static err_t tcp_echoserver_accept(void *arg, struct tcp_pcb *newpcb, err_t err);
static err_t tcp_echoserver_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err);
static void tcp_echoserver_error(void *arg, err_t err);
static err_t tcp_echoserver_poll(void *arg, struct tcp_pcb *tpcb);
static err_t tcp_echoserver_sent(void *arg, struct tcp_pcb *tpcb, u16_t len);
static void tcp_echoserver_send(struct tcp_pcb *tpcb, struct tcp_echoserver_struct *es);
static void tcp_echoserver_connection_close(struct tcp_pcb *tpcb, struct tcp_echoserver_struct *es);
/* structure for maintaing connection infos to be passed as argument
to LwIP callbacks*/
struct tcp_echoserver_struct
{
u8_t state; /* current connection state */
u8_t retries;
struct tcp_pcb *pcb; /* pointer on the current tcp_pcb */
struct pbuf *p; /* pointer on the received/to be transmitted pbuf */
};
/**
* @brief Initializes the tcp echo server
* @param None
* @retval None
*/
void tcp_echoserver_init(void)
{
/* create new tcp pcb */
tcp_echoserver_pcb = tcp_new();
//内存块是动态分配的,需要判断是否创建成功
if (tcp_echoserver_pcb != NULL)
{
err_t err;
/*
针对我们创建的tcp控制块,绑定本机的ip第一种,以及端口7
*/
err = tcp_bind(tcp_echoserver_pcb, IP_ADDR_ANY, 7);
if (err == ERR_OK)
{
/*
开启监听
监听返回值为一个新的tcp的控制块,如果监听成功,之前的控制块就会释放掉
*/
tcp_echoserver_pcb = tcp_listen(tcp_echoserver_pcb);
/*
等待客户端连接
这里用回调的形式实现的,就是tcp_echoserver_accept
*/
tcp_accept(tcp_echoserver_pcb, tcp_echoserver_accept);
}
else
{
/*
如果绑定失败,释放掉tcp控制块
*/
memp_free(MEMP_TCP_PCB, tcp_echoserver_pcb);
}
}
}
/**
* @brief This function is the implementation of tcp_accept LwIP callback
* @param arg: not used
* @param newpcb: 指向客户端的tcp的控制块
* @param err: not used
* @retval err_t: error status
*/
static err_t tcp_echoserver_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
{
err_t ret_err;
//这是整个echoserver的控制块(结构体)
struct tcp_echoserver_struct *es;
LWIP_UNUSED_ARG(arg);
LWIP_UNUSED_ARG(err);
/* 设置客户端的tcp的优先级为最低 */
tcp_setprio(newpcb, TCP_PRIO_MIN);
/* 动态分配的 tcp_echoserver_struct */
es = (struct tcp_echoserver_struct *)mem_malloc(sizeof(struct tcp_echoserver_struct));
//只有涉及到动态分配,都需要判断返回地址是否正确
if (es != NULL)
{
//当前的server的状态为客户接入完成
es->state = ES_ACCEPTED;
//pcb指向客户的tcp控制块
es->pcb = newpcb;
//重发次数,赋值为0
es->retries = 0;
//数据接收/发送的缓冲区指向空
es->p = NULL;
/*
每一pcb控制块里面成员很多,有一个成员就是专门存放跟当前tcp相关的参数
把我们整个程序用的tcp_echoserver_struct,当做参数传入到我们的pcb控制块中
*/
tcp_arg(newpcb, es);
/*
初始化 接收的回调函数 tcp_echoserver_recv
*/
tcp_recv(newpcb, tcp_echoserver_recv);
/* 初始化错误产生后的回调函数 */
tcp_err(newpcb, tcp_echoserver_error);
/*初始化 轮询的回调函数,但是 intercal值为0,就是不启用轮询功能*/
tcp_poll(newpcb, tcp_echoserver_poll, 0);
ret_err = ERR_OK;
}//创建tcp_echoserver_struct 失败
else
{
/* 关闭tcp连接 */
tcp_echoserver_connection_close(newpcb, es);
/* 返回内存分配失败 */
ret_err = ERR_MEM;
}
return ret_err;
}
/**
* @brief This function is the implementation for tcp_recv LwIP callback
* @param arg: 这个就是tcp_echoserver_struct
* @param tpcb: 当前使用tcp控制块
* @param pbuf: 指向了接收到数据的缓冲区,这个pbuf是lwip内部接收到数据后,自动分配的
* @param err: 错误信息
* @retval err_t: error code
*/
static err_t tcp_echoserver_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{
struct tcp_echoserver_struct *es;
err_t ret_err;
LWIP_ASSERT("arg != NULL",arg != NULL);
//获取到当前tcp_echoserver_struct
es = (struct tcp_echoserver_struct *)arg;
/* 接收到的数据为空 */
if (p == NULL)
{
/* 改变状态为关闭*/
es->state = ES_CLOSING;
//判断我们是否还需要发送数据
if(es->p == NULL)
{
/*不许发送,直接关闭tcp连接*/
tcp_echoserver_connection_close(tpcb, es);
}
else
{
/*创建发送数据完成后的回调函数*/
tcp_sent(tpcb, tcp_echoserver_sent);
/* 触发发送,真正的发送到网卡上*/
tcp_echoserver_send(tpcb, es);
}
ret_err = ERR_OK;
}
/* 收到数据了,但是产生错误了 */
else if(err != ERR_OK)
{
/* 释放接收的缓冲区*/
if (p != NULL)
{
es->p = NULL;
pbuf_free(p);
}
ret_err = err;
}
else if(es->state == ES_ACCEPTED)
{
/* 改变状态为 接收 */
es->state = ES_RECEIVED;
/* 把接收的pbuf的地址,存取到我们的本地结构体里 */
es->p = p;
/* 进行应答------ 我们功能是回显,回响 */
tcp_sent(tpcb, tcp_echoserver_sent);
/* 直接发送数据到网卡 */
tcp_echoserver_send(tpcb, es);
ret_err = ERR_OK;
}
else if (es->state == ES_RECEIVED)
{
/* 判断 我们的发送缓冲区里面,是否有未发的数据,没有*/
if(es->p == NULL)
{
//把pbuf进行存储
es->p = p;
/* 进行发送 */
tcp_echoserver_send(tpcb, es);
}//有数据需要发送
else
{
struct pbuf *ptr;
/*
由于之前数据没有发送完成,需要进行数据连接
*/
ptr = es->p;//把之前待发送的地址获取到
pbuf_chain(ptr,p);//进行首尾连接
}
ret_err = ERR_OK;
}//处于关闭状态
else if(es->state == ES_CLOSING)
{
/*
释放pbuf
*/
tcp_recved(tpcb, p->tot_len);
es->p = NULL;
pbuf_free(p);
ret_err = ERR_OK;
}
else
{
/* 释放pbuf */
tcp_recved(tpcb, p->tot_len);
es->p = NULL;
pbuf_free(p);
ret_err = ERR_OK;
}
return ret_err;
}
/**
* @brief 当产生错误时,lwip调用此函数
* @param arg: 指向我们 tcp_echoserver_struct
* @param err: not used
* @retval None
*/
static void tcp_echoserver_error(void *arg, err_t err)
{
struct tcp_echoserver_struct *es;
LWIP_UNUSED_ARG(err);
es = (struct tcp_echoserver_struct *)arg;
if (es != NULL)
{
/* 释放 tcp_echoserver_struct */
mem_free(es);
}
}
/**
* @brief This function implements the tcp_poll LwIP callback function
* @param arg: pointer on argument passed to callback
* @param tpcb: pointer on the tcp_pcb for the current tcp connection
* @retval err_t: error code
*/
static err_t tcp_echoserver_poll(void *arg, struct tcp_pcb *tpcb)
{
err_t ret_err;
struct tcp_echoserver_struct *es;
es = (struct tcp_echoserver_struct *)arg;
if (es != NULL)
{
//有数据需要发送
if (es->p != NULL)
{
tcp_sent(tpcb, tcp_echoserver_sent);
/* there is a remaining pbuf (chain) , try to send data */
tcp_echoserver_send(tpcb, es);
}
else
{
/* 判断状态是否为关闭 */
if(es->state == ES_CLOSING)
{
/* 关闭tcp连接 */
tcp_echoserver_connection_close(tpcb, es);
}
}
ret_err = ERR_OK;
} //没有创建tcp_echoserver_struct
else
{
/* 终止 tcp任务 */
tcp_abort(tpcb);
ret_err = ERR_ABRT;
}
return ret_err;
}
/**
* @brief 当发送完成以后,会调用这个回调函数
* @param None
* @retval None
*/
static err_t tcp_echoserver_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
{
struct tcp_echoserver_struct *es;
LWIP_UNUSED_ARG(len);
es = (struct tcp_echoserver_struct *)arg;
es->retries = 0;
if(es->p != NULL)
{
/* 还有数据需要继续发送 */
tcp_sent(tpcb, tcp_echoserver_sent);
tcp_echoserver_send(tpcb, es);
}
else
{
/* 需要关闭,我们才关闭*/
if(es->state == ES_CLOSING)
tcp_echoserver_connection_close(tpcb, es);
}
return ERR_OK;
}
/**
* @brief 把数据发送到网卡
* @param tpcb: pointer on the tcp_pcb connection
* @param es: pointer on echo_state structure
* @retval None
*/
static void tcp_echoserver_send(struct tcp_pcb *tpcb, struct tcp_echoserver_struct *es)
{
struct pbuf *ptr;
err_t wr_err = ERR_OK;
//做个三个判断
/*
1、tcp任务没有出错
2、有待发送的数据
3、将要发送的数据,长度小于 tcp发送长度
3.1、 tcp发送buf,有限制的,不是无穷大的,我们要发送长度,不能大于它,如果大于它就会出错
*/
while ((wr_err == ERR_OK) &&
(es->p != NULL) &&
(es->p->len <= tcp_sndbuf(tpcb)))
{
/* 获取到待发送的pbuf的指针*/
ptr = es->p;
/* 调用write进行发送,发送到网卡上 */
wr_err = tcp_write(tpcb, ptr->payload, ptr->len, 1);
if (wr_err == ERR_OK)
{
u16_t plen;
u8_t freed;
//获取剩余长度
plen = ptr->len;
/* 如果这个pbuf链表还有其他的,再此发送 */
es->p = ptr->next;
if(es->p != NULL)
{
/* 刷新计数值 */
pbuf_ref(es->p);
}
/* */
do
{
/* 释放pbuf */
freed = pbuf_free(ptr);
}
while(freed == 0);
/* 进行接收 */
tcp_recved(tpcb, plen);
}
else if(wr_err == ERR_MEM)
{
/* 进行重发 */
es->p = ptr;
}
else
{
/* other problem ?? */
}
}
}
/**
* @brief This functions closes the tcp connection
* @param tcp_pcb: pointer on the tcp connection
* @param es: pointer on echo_state structure
* @retval None
*/
static void tcp_echoserver_connection_close(struct tcp_pcb *tpcb, struct tcp_echoserver_struct *es)
{
/* 移植所有的回调函数 */
tcp_arg(tpcb, NULL);
tcp_sent(tpcb, NULL);
tcp_recv(tpcb, NULL);
tcp_err(tpcb, NULL);
tcp_poll(tpcb, NULL, 0);
/* 释放 tcp_echoserver_struct 内存空间*/
if (es != NULL)
{
mem_free(es);
}
/* 关闭tcp连接,这里会释放pcb控制块的内存 */
tcp_close(tpcb);
}