STM32移植lwip之建立tcp服务器

本篇目标:在之前能ping通pc机的工程基础上搭建tcp连接,并可以收发数据,在网络调试工具上显示

材料准备:

  • 基础工程:修改后能ping通pc机的工程(STM32官方移植lwip修改代码)
  • 调试工具:用来调试tcp连接下的数据接收(网络调试助手)
  • 搭建工程:最终搭建好tcp数据接收的工程(tcp服务器建立工程)

搭建TCP服务器

之前已经能够让pc机ping通stm32了,说明PHY网卡已经正确工作了,现在可以使用lwip的函数来建立tcp服务器了;
现在创建一个新的c文件,取名为 tcp_server.c ,接下来要写三个函数:

  • tcp服务器初始化函数 Tcp_Server_Init():
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端口号、监听数据、设置接收数据回调函数;

  • 接收数据回调函数 tcp_server_accept() :
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() :
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”

文件源码

  • tcp_server.c
#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;
}
  • tcp_server.h
#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 */

tcp服务器收发测试

将工程编译后,烧进stm32,将网线与pc机连接,打开网络调试助手:

  1. 顶部菜单选择网络调试
  2. 输入目标ip地址(我的stm32 ip地址:192.168.0.10)点击ping,ping通就ok
  3. 目标端口输入80
  4. 点击辅助-打开TCP,变成绿色,显示TCP连接成功
  5. 在发送区输入任意字符,点击TCP发送,接收区则显示你发送的字符

有图有真相:

STM32移植lwip之建立tcp服务器_第1张图片


总结:上面只是搭建了最简单的tcp服务器用来收发数据,理清tcp服务器建立过程再去看官网建立tcp服务器的程序,就会看的更加的明白,上面注释的也是函数表面的一些功能,没有很深入讲解,还需要多看看lwip的源码分析才能深刻了解几个建立tcp服务器的函数的机制作用,共勉~

你可能感兴趣的:(stm32学习lwip移植)