本篇目标:在之前能ping通pc机的工程基础上搭建tcp连接,并可以收发数据,在网络调试工具上显示
材料准备:
之前已经能够让pc机ping通stm32了,说明PHY网卡已经正确工作了,现在可以使用lwip的函数来建立tcp服务器了;
现在创建一个新的c文件,取名为 tcp_server.c ,接下来要写三个函数:
void Tcp_Server_Init(void)
{
struct tcp_pcb *tcp_server_pcb;
/* 为tcp服务器分配一个tcp_pcb结构体 */
tcp_server_pcb = tcp_new();
/* 绑定本地端号和IP地址 */
tcp_bind(tcp_server_pcb, IP_ADDR_ANY, 80);
/* 监听之前创建的结构体tcp_server_pcb */
tcp_server_pcb = tcp_listen(tcp_server_pcb);
/* 初始化结构体接收回调函数 */
tcp_accept(tcp_server_pcb, tcp_server_accept);
}
小结:上面函数主要就是为搭建tcp连接做准备,包括申请网络结构体、设置80端口号、监听数据、设置接收数据回调函数;
static err_t tcp_server_accept(void *arg, struct tcp_pcb *pcb, err_t err)
{
/* 确认监听与连接 */
tcp_arg(pcb, mem_calloc(sizeof(struct name), 1));
/* 发送一个建立连接的字符串 */
tcp_write(pcb, "hello my dream \n\r",strlen("hello my dream \n\r "), 1);
/* 配置接收回调函数 */
tcp_recv(pcb, tcp_server_recv);
return ERR_OK;
}
小结:这个函数最重要的就是最后一个函数,它指向了处理接收数据的函数;
static err_t tcp_server_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *tcp_recv_pbuf, err_t err)
{
struct pbuf *tcp_send_pbuf;
struct name *name = (struct name *)arg;
if (tcp_recv_pbuf != NULL)
{
/* 扩大收发数据的窗口 */
tcp_recved(pcb, tcp_recv_pbuf->tot_len);
if (!name)
{
pbuf_free(tcp_recv_pbuf);
return ERR_ARG;
}
/* 将接收的数据拷贝给发送结构体 */
tcp_send_pbuf = tcp_recv_pbuf;
/* 换行 */
tcp_write(pcb, "\r\n", strlen("\r\n"), 1);
/* 将接收到的数据再转发出去 */
tcp_write(pcb, tcp_send_pbuf->payload, tcp_send_pbuf->len, 1);
pbuf_free(tcp_recv_pbuf);
}
else if (err == ERR_OK)
{
/* 释放内存 */
mem_free(name);
return tcp_close(pcb);
}
return ERR_OK;
}
小结:此函数将接收到的数据拷贝一份,然后再发送出去,实现简单的收发工程测试;
ps:tcp_server.c 还有头文件的包含,函数的定义;另外再编写一个tcp_server.h文件,包含宏定义,结构体定义,函数定义;在下面贴出这两个文件的源码;
接下来,只要在main函数添加初始化函数Tcp_Server_Init()就可以了,添加在while循环和lwip_init()之间就可以了,还不要忘了 #include “tcp_server.h”
#include "lwip/debug.h"
#include "lwip/stats.h"
#include "lwip/tcp.h"
#include "tcp_server.h"
#include
#include
#include
/*
*********************************************************************************************************
* LOCAL TABLES
*********************************************************************************************************
*/
static err_t tcp_server_accept(void *arg, struct tcp_pcb *pcb, err_t err);
static err_t tcp_server_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);
/*
*********************************************************************************************************
* LOCAL FUNCTION PROTOTYPES
*********************************************************************************************************
*/
/***
* 函数名称 : Tcp_Server_Init();
*
* 函数描述 : TCP服务器初始化;
*
* 传递值 : 无;
*
* 返回值 : 无;
*
**/
void Tcp_Server_Init(void)
{
struct tcp_pcb *tcp_server_pcb;
/* 为tcp服务器分配一个tcp_pcb结构体 */
tcp_server_pcb = tcp_new();
/* 绑定本地端号和IP地址 */
tcp_bind(tcp_server_pcb, IP_ADDR_ANY, 80);
/* 监听之前创建的结构体tcp_server_pcb */
tcp_server_pcb = tcp_listen(tcp_server_pcb);
/* 初始化结构体接收回调函数 */
tcp_accept(tcp_server_pcb, tcp_server_accept);
}
/***
* 函数名称 : tcp_server_accept();
*
* 函数描述 : lwip数据接收回调函数,包含对tcp连接的确认,接收回调函数的配置;
*
* 传递值 : *arg, *pcb, err ;
*
* 返回值 : ERR_OK 无错误;
*
**/
static err_t tcp_server_accept(void *arg, struct tcp_pcb *pcb, err_t err)
{
/* 确认监听与连接 */
tcp_arg(pcb, mem_calloc(sizeof(struct name), 1));
/* 发送一个建立连接的字符串 */
tcp_write(pcb, "hello my dream \n\r",strlen("hello my dream \n\r "), 1);
/* 配置接收回调函数 */
tcp_recv(pcb, tcp_server_recv);
return ERR_OK;
}
/***
* 函数名称 : tcp_server_recv();
*
* 函数描述 : 接受到数据后,将数据拷贝转发出去;
*
* 传递值 : *arg, *pcb, *tcp_recv_pbuf, err;
*
* 返回值 : ERR_ARG 非法逻辑,ERR_OK无错误;
*
**/
static err_t tcp_server_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *tcp_recv_pbuf, err_t err)
{
struct pbuf *tcp_send_pbuf;
struct name *name = (struct name *)arg;
if (tcp_recv_pbuf != NULL)
{
/* 扩大收发数据的窗口 */
tcp_recved(pcb, tcp_recv_pbuf->tot_len);
if (!name)
{
pbuf_free(tcp_recv_pbuf);
return ERR_ARG;
}
/* 将接收的数据拷贝给发送结构体 */
tcp_send_pbuf = tcp_recv_pbuf;
/* 换行 */
tcp_write(pcb, "\r\n", strlen("\r\n"), 1);
/* 将接收到的数据再转发出去 */
tcp_write(pcb, tcp_send_pbuf->payload, tcp_send_pbuf->len, 1);
pbuf_free(tcp_recv_pbuf);
}
else if (err == ERR_OK)
{
/* 释放内存 */
mem_free(name);
return tcp_close(pcb);
}
return ERR_OK;
}
#ifndef TCP_SERVER_H
#define TCP_SERVER_H
/*
*********************************************************************************************************
* INCLUDE FILES
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* CONSTANTS
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* PERIPH DEFINES
*********************************************************************************************************
*/
#define MAX_NAME_SIZE 32
struct name
{
int length;
char bytes[MAX_NAME_SIZE];
};
/*
*********************************************************************************************************
* DATA TYPES
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* GLOBAL VARIABLES
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* MACRO'S
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* FUNCTION PROTOTYPES
*********************************************************************************************************
*/
void Tcp_Server_Init(void);
/*
********************************************************************************************************
* MODULE END
*********************************************************************************************************
*/
#endif /* TCP_SERVER_H */
将工程编译后,烧进stm32,将网线与pc机连接,打开网络调试助手:
有图有真相:
总结:上面只是搭建了最简单的tcp服务器用来收发数据,理清tcp服务器建立过程再去看官网建立tcp服务器的程序,就会看的更加的明白,上面注释的也是函数表面的一些功能,没有很深入讲解,还需要多看看lwip的源码分析才能深刻了解几个建立tcp服务器的函数的机制作用,共勉~