STM32移植lwip之建立tcp服务器

来源:互联网 发布:缩小手机屏幕的软件 编辑:程序博客网 时间:2024/05/20 12:22

本篇目标:在之前能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 <string.h>#include <stdio.h>#include <stdlib.h>/***********************************************************************************************************                                            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       32struct 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发送,接收区则显示你发送的字符

有图有真相:

tcp服务器收发测试


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

0 0
原创粉丝点击