单片机IWIPTCP客户端/服务器实验

单片机 :STM32F407

开发板:DMF407电机开发板

平台:keil V5.31

HSE 为8MHZ

HSI为16MHZ

一、客户端

主函数

复制代码
void lwip_test_ui(uint8_t mode)
{
    uint8_t speed;
    uint8_t buf[30];
    
    if(mode & 1<< 0)
    {
        lcd_show_string(6, 10, 200, 32, 32, "STM32", DARKBLUE);
        lcd_show_string(6, 40, lcddev.width, 24, 24, "lwIP TCPClient Test", DARKBLUE);
        lcd_show_string(6, 70, 200, 16, 16, "ATOM@ALIENTEK", DARKBLUE);
    }
    
    if(mode & 1 << 1)
    {
        lcd_show_string(6, 110, 200, 16, 16, "lwIP Init Successed", MAGENTA);
        
        if(g_lwipdev.dhcpstatus == 2)
        {
            sprintf((char*)buf,"DHCP IP:%d.%d.%d.%d",g_lwipdev.ip[0],g_lwipdev.ip[1],g_lwipdev.ip[2],g_lwipdev.ip[3]);      /* 显示动态IP地址 */
        }
        else
        {
            sprintf((char*)buf,"Static IP:%d.%d.%d.%d",g_lwipdev.ip[0],g_lwipdev.ip[1],g_lwipdev.ip[2],g_lwipdev.ip[3]);    /* 打印静态IP地址 */
        }
        
        lcd_show_string(6, 130, 200, 16, 16, (char*)buf, MAGENTA);
        
        speed = ethernet_chip_get_speed();                                                                                  /* 得到网速 */
        
        if(speed)
        {
            lcd_show_string(6, 150, 200, 16, 16, "Ethernet Speed:100M", MAGENTA);
        }
        else
        {
            lcd_show_string(6, 150, 200, 16, 16, "Ethernet Speed:10M", MAGENTA);
        }
    }
}

int main(void)
{
    uint8_t key;

    HAL_Init();                         /* 初始化HAL库 */
    sys_stm32_clock_init(336, 8, 2, 7); /* 设置时钟,168Mhz */
    delay_init(168);                    /* 延时初始化 */
    usart_init(115200);                 /* 串口初始化为115200 */
    usmart_dev.init(84);                /* 初始化USMART */
    led_init();                         /* 初始化LED */
    lcd_init();                         /* 初始化LCD */
    key_init();                         /* 初始化按键 */
    
    my_mem_init(SRAMIN);                /* 初始化内部SRAM内存池 */
    my_mem_init(SRAMCCM);               /* 初始化内部SRAMCCM内存池 */

    lwip_test_ui(1);                    /* 加载前半部分UI */

    lcd_show_string(6, 110, 200, 16, 16, "lwIP Init !!", BLUE);
    
    while (lwip_comm_init() != 0)
    {
        lcd_show_string(6, 110, 200, 16, 16, "lwIP Init failed!!", BLUE);
        delay_ms(500);
        lcd_fill(6, 50, 200 + 30, 50 + 16, WHITE);
        lcd_show_string(6, 110, 200, 16, 16, "Retrying...       ", BLUE);
        delay_ms(500);
        LED1_TOGGLE();
    }

    while (!ethernet_read_phy(PHY_SR))  /* 检查MCU与PHY芯片是否通信成功 */
    {
        printf("MCU与PHY芯片通信失败,请检查电路或者源码!!!!\r\n");
    }
    
#if LWIP_DHCP
    lcd_show_string(6, 130, 200, 16, 16, "DHCP IP configing... ", BLUE);    /* 开始DHCP */
    
    while ((g_lwipdev.dhcpstatus != 2)&&(g_lwipdev.dhcpstatus != 0XFF))     /* 等待DHCP获取成功/超时溢出 */
    {
        lwip_periodic_handle();
    }
#endif
    
    lwip_demo();                        /* lwIP程序入口 */
    
    lwip_test_ui(2);                    /* 加载后半部分UI */
    
    while(1)
    {
        lwip_periodic_handle();         /* LWIP轮询任务 */
        
        key = key_scan(0);
        
        if (key == KEY1_PRES)
        {
            if((g_lwip_send_flag & 1 << 5)) 
            {
                printf("连接已经建立,不能重复连接\r\n"); /* 如果连接成功,不做任何处理 */
            }
            else 
            {
                lwip_demo();            /* 当断开连接后,调用lwip_demo()函数 */
            }
        }
        
        delay_ms(10);
    }
}

void lwip_demo(void)
{
    struct tcp_pcb *tcppcb;   /* 定义一个TCP客户端控制块 */
    ip_addr_t rmtipaddr;      /* 远端ip地址 */

    char *tbuf;
    uint8_t key;
    uint8_t res = 0;
    uint8_t t = 0;

    lwip_tcp_client_set_remoteip();  /* 先选择IP */
    lcd_clear(WHITE);                /* 清屏 */
    g_point_color = RED;
    lcd_show_string(5, 30, 200, 16, 16, "STM32", g_point_color);
    lcd_show_string(5, 50, 200, 16, 16, "TCP Client Test", g_point_color);
    lcd_show_string(5, 70, 200, 16, 16, "ATOM@ALIENTEK", g_point_color);
    lcd_show_string(5, 90, 200, 16, 16, "KEY0:Send data", g_point_color);
    lcd_show_string(5, 110, 200, 16, 16, "KEY1:Quit", g_point_color);
    tbuf = mymalloc(SRAMIN, 200); /* 申请内存 */

    if (tbuf == NULL)return ;     /* 内存申请失败了,直接退出 */

    sprintf((char *)tbuf, "Local IP:%d.%d.%d.%d", g_lwipdev.ip[0], g_lwipdev.ip[1], g_lwipdev.ip[2], g_lwipdev.ip[3]); /* 服务器IP */
    lcd_show_string(5, 130, 210, 16, 16, tbuf, g_point_color);
    sprintf((char *)tbuf, "Remote IP:%d.%d.%d.%d", g_lwipdev.remoteip[0], g_lwipdev.remoteip[1], g_lwipdev.remoteip[2], g_lwipdev.remoteip[3]); /* 远端IP */
    lcd_show_string(5, 150, 210, 16, 16, tbuf, g_point_color);
    sprintf((char *)tbuf, "Remote Port:%d", LWIP_DEMO_PORT); /* 客户端端口号 */
    lcd_show_string(5, 170, 210, 16, 16, tbuf, g_point_color);
    g_point_color = BLUE;
    lcd_show_string(5, 190, 210, 16, 16, "STATUS:Disconnected", g_point_color);
    tcppcb = tcp_new();  /* 创建一个新的pcb */

    if (tcppcb)           /* 创建成功 */
    {
        IP4_ADDR(&rmtipaddr, g_lwipdev.remoteip[0], g_lwipdev.remoteip[1], g_lwipdev.remoteip[2], g_lwipdev.remoteip[3]);
        tcp_connect(tcppcb, &rmtipaddr, LWIP_DEMO_PORT, lwip_tcp_client_connected); /* 连接到目的地址的指定端口上,当连接成功后回调lwip_tcp_client_connected()函数 */
    }
    else res = 1;

    while (res == 0)
    {
        key = key_scan(0);

        if (key == KEY1_PRES)break;

        if (key == KEY0_PRES)                       /* KEY0按下了,发送数据 */
        {
            lwip_tcp_client_usersent(tcppcb);       /* 发送数据 */
        }

        if (g_lwip_send_flag & 1 << 6)              /* 是否收到数据 */
        {
            lcd_fill(5, 230, lcddev.width - 1, lcddev.height - 1, WHITE);                                                       /* 清上一次数据 */
            lcd_show_string(5, 230, lcddev.width - 30, lcddev.height - 230, 16, (char *)g_lwip_demo_recvbuf, g_point_color);    /* 显示接收到的数据 */
            g_lwip_send_flag &= ~(1 << 6);          /* 标记数据已经被处理了 */
        }

        if (g_lwip_send_flag & 1 << 5)              /* 是否连接上 */
        {
            lcd_show_string(5, 190, lcddev.width - 30, lcddev.height - 190, 16, "STATUS:Connected   ", g_point_color);          /* 提示消息 */
            g_point_color = RED;
            lcd_show_string(5, 210, lcddev.width - 30, lcddev.height - 190, 16, "Receive Data:", g_point_color);                /* 提示消息 */
            g_point_color = BLUE;
        }
        else if ((g_lwip_send_flag & 1 << 5) == 0)
        {
            lcd_show_string(5, 190, 190, 16, 16, "STATUS:Disconnected", g_point_color);
            lcd_fill(5, 210, lcddev.width - 1, lcddev.height - 1, WHITE);       /* 清屏 */
        }

        lwip_periodic_handle();                                                 /* LWIP轮询任务 */
        
        delay_ms(2);
        t++;

        if (t == 200)
        {
            if ((g_lwip_send_flag & 1 << 5) == 0)                               /* 未连接上,则尝试重连 */
            {
                lwip_tcp_client_connection_close(tcppcb, 0);                    /* 关闭连接 */
                tcppcb = tcp_new();                                             /* 创建一个新的pcb */

                if (tcppcb)                                                     /* 创建成功 */
                {
                    tcp_connect(tcppcb, &rmtipaddr, LWIP_DEMO_PORT, lwip_tcp_client_connected); /* 连接到目的地址的指定端口上,当连接成功后回调lwip_tcp_client_connected()函数 */
                }
            }

            t = 0;
            LED0_TOGGLE();
        }
    }
    
    lwip_tcp_client_connection_close(tcppcb, 0);    /* 关闭TCP Client连接 */
    lcd_clear(WHITE);                               /* 清屏 */
    g_point_color = DARKBLUE;
    lcd_show_string(5, 30, 200, 16, 16, "STM32", g_point_color);
    lcd_show_string(5, 50, 200, 16, 16, "TCPclient Test", g_point_color);
    lcd_show_string(5, 70, 200, 16, 16, "ATOM@ALIENTEK", g_point_color);
    lcd_show_string(5, 90, 200, 16, 16, "KEY1:Connect", g_point_color);
    lcd_show_string(5, 190, 210, 16, 16, "STATUS:Disconnected", g_point_color);
    myfree(SRAMIN, tbuf);
}

测试结果:

二、服务器

复制代码
/* tcp服务器连接状态 */
enum tcp_server_states
{
    ES_TCPSERVER_NONE = 0,                  /* 初始化 */
    ES_TCPSERVER_ACCEPTED,                  /* 连接状态 */
    ES_TCPSERVER_CLOSING,                   /* 关闭连接状态 */
};

/* LWIP回调函数使用的结构体 */
struct tcp_server_struct
{
    uint8_t state;                          /* 当前状态 */
    struct tcp_pcb *pcb;                    /* 指向TCP控制块 */
    struct pbuf *p;                         /* 指向接收/传输的pbuf */
};

err_t lwip_tcp_server_accept(void *arg,struct tcp_pcb *newpcb,err_t err);
err_t lwip_tcp_server_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err);
void lwip_tcp_server_error(void *arg,err_t err);
err_t lwip_tcp_server_usersent(struct tcp_pcb *tpcb);
err_t lwip_tcp_server_poll(void *arg, struct tcp_pcb *tpcb);
err_t lwip_tcp_server_sent(void *arg, struct tcp_pcb *tpcb, u16_t len);
void lwip_tcp_server_senddata(struct tcp_pcb *tpcb, struct tcp_server_struct *es);
void lwip_tcp_server_connection_close(struct tcp_pcb *tpcb, struct tcp_server_struct *es);
void lwip_tcp_server_remove_timewait(void);

/**
 * @brief       lwip_demo 测试
 * @param       无
 * @retval      无
 */
void lwip_demo(void)
{
    err_t err;
    struct tcp_pcb *tcppcbnew;          /* 定义一个TCP服务器控制块 */
    struct tcp_pcb *tcppcbconn;         /* 定义一个TCP服务器控制块 */

    char *tbuf;
    uint8_t key;
    uint8_t res = 0;
    uint8_t t = 0;

    lcd_clear(WHITE);                   /* 清屏 */
    g_point_color = RED;
    lcd_show_string(5, 30, 200, 16, 16, "STM32", g_point_color);
    lcd_show_string(5, 50, 200, 16, 16, "TCP Server Test", g_point_color);
    lcd_show_string(5, 70, 200, 16, 16, "ATOM@ALIENTEK", g_point_color);
    lcd_show_string(5, 90, 200, 16, 16, "KEY0:Send data", g_point_color);
    tbuf = mymalloc(SRAMIN, 200);       /* 申请内存 */

    if (tbuf == NULL)return ;           /* 内存申请失败了,直接退出 */

    sprintf((char *)tbuf, "Server IP:%d.%d.%d.%d", g_lwipdev.ip[0], g_lwipdev.ip[1], g_lwipdev.ip[2], g_lwipdev.ip[3]); /* 服务器IP */
    lcd_show_string(5, 130, 210, 16, 16, tbuf, g_point_color);
    sprintf((char *)tbuf, "Server Port:%d", LWIP_DEMO_PORT);                                                            /* 服务器端口号 */
    lcd_show_string(5, 150, 210, 16, 16, tbuf, g_point_color);
    tcppcbnew = tcp_new();              /* 创建一个新的pcb */

    if (tcppcbnew)                      /* 创建成功 */
    {
        err = tcp_bind(tcppcbnew, IP_ADDR_ANY, LWIP_DEMO_PORT); /* 将本地IP与指定的端口号绑定在一起,IP_ADDR_ANY为绑定本地所有的IP地址 */

        if (err == ERR_OK)              /* 绑定完成 */
        {
            tcppcbconn = tcp_listen(tcppcbnew);                 /* 设置tcppcb进入监听状态 */
            tcp_accept(tcppcbconn, lwip_tcp_server_accept);     /* 初始化LWIP的tcp_accept的回调函数 */
        }
        else res = 1;
    }
    else res = 1;

    g_point_color = BLUE;

    while (res == 0)
    {
        key = key_scan(0);

        if (key == KEY0_PRES)                                   /* KEY0按下了,发送数据 */
        {
            lwip_tcp_server_usersent(tcppcbnew);                /* 发送数据 */
        }

        if (g_lwip_send_flag & 1 << 6)                          /* 是否收到数据 */
        {
            lcd_fill(5, 210, lcddev.width - 1, lcddev.height - 1, WHITE);                                                       /* 清上一次数据 */
            lcd_show_string(5, 210, lcddev.width - 30, lcddev.height - 210, 16, (char *)g_lwip_demo_recvbuf, g_point_color);    /* 显示接收到的数据 */
            g_lwip_send_flag &= ~(1 << 6);                      /* 标记数据已经被处理了 */
        }

        if (g_lwip_send_flag & 1 << 5)                          /* 是否连接上 */
        {
            sprintf((char *)tbuf, "Client IP:%d.%d.%d.%d", g_lwipdev.remoteip[0], g_lwipdev.remoteip[1], g_lwipdev.remoteip[2], g_lwipdev.remoteip[3]); /* 客户端IP */
            lcd_show_string(5, 170, 230, 16, 16, tbuf, g_point_color);
            g_point_color = RED;
            lcd_show_string(5, 190, lcddev.width - 30, lcddev.height - 190, 16, "Receive Data:", g_point_color); /* 提示消息 */
            g_point_color = BLUE;
        }
        else if (g_lwip_send_flag & 1 << 5)
        {
            lcd_fill(5, 170, lcddev.width - 1, lcddev.height - 1, WHITE);   /* 清屏 */
        }

        lwip_periodic_handle();
        delay_ms(2);
        t++;

        if (t == 200)
        {
            t = 0;
            LED0_TOGGLE();
        }
    }
}

/**
 * @brief       lwIP tcp_accept()的回调函数
 * @param       arg :传入的参数
 * @param       newpcb:TCP控制块
 * @param       err :错误码
 * @retval      返回 ret_err
 */
err_t lwip_tcp_server_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
{
    err_t ret_err;
    struct tcp_server_struct *es;
    LWIP_UNUSED_ARG(arg);
    LWIP_UNUSED_ARG(err);
    tcp_setprio(newpcb, TCP_PRIO_MIN);                                  /* 设置新创建的pcb优先级 */
    es = (struct tcp_server_struct *)mem_malloc(sizeof(struct tcp_server_struct)); /* 分配内存 */

    if (es != NULL)                                                     /* 内存分配成功 */
    {
        es->state = ES_TCPSERVER_ACCEPTED;                              /* 接收连接 */
        es->pcb = newpcb;
        es->p = NULL;
        
        tcp_arg(newpcb, es);
        tcp_recv(newpcb, lwip_tcp_server_recv);                         /* 初始化tcp_recv()的回调函数 */
        tcp_err(newpcb, lwip_tcp_server_error);                         /* 初始化tcp_err()回调函数 */
        tcp_poll(newpcb, lwip_tcp_server_poll, 1);                      /* 初始化tcp_poll回调函数 */
        tcp_sent(newpcb, lwip_tcp_server_sent);                         /* 初始化发送回调函数 */

        g_lwip_send_flag |= 1 << 5;                                     /* 标记有客户端连上了 */
        g_lwipdev.remoteip[0] = newpcb->remote_ip.addr & 0xff;          /* IADDR4 */
        g_lwipdev.remoteip[1] = (newpcb->remote_ip.addr >> 8) & 0xff;   /* IADDR3 */
        g_lwipdev.remoteip[2] = (newpcb->remote_ip.addr >> 16) & 0xff;  /* IADDR2 */
        g_lwipdev.remoteip[3] = (newpcb->remote_ip.addr >> 24) & 0xff;  /* IADDR1 */
        ret_err = ERR_OK;
    }
    else
    {
        ret_err = ERR_MEM;
    }

    return ret_err;
}

/**
 * @brief       lwIP tcp_recv()函数的回调函数
 * @param       arg :传入的参数
 * @param       tpcb:TCP控制块
 * @param       p   :网络数据包
 * @param       err :错误码
 * @retval      返回 ret_err
 */
err_t lwip_tcp_server_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{
    err_t ret_err;
    uint32_t data_len = 0;
    struct pbuf *q;
    struct tcp_server_struct *es;
    LWIP_ASSERT("arg != NULL", arg != NULL);
    es = (struct tcp_server_struct *)arg;

    if (p == NULL)                                                          /* 从客户端接收到空数据 */
    {
        es->state = ES_TCPSERVER_CLOSING;                                   /* 需要关闭TCP 连接了 */
        es->p = p;
        ret_err = ERR_OK;
    }
    else if (err != ERR_OK)                                                 /* 从客户端接收到一个非空数据,但是由于某种原因err!=ERR_OK */
    {
        if (p)pbuf_free(p);                                                 /* 释放接收pbuf */

        ret_err = err;
    }
    else if (es->state == ES_TCPSERVER_ACCEPTED)                            /* 处于连接状态 */
    {
        if (p != NULL)                                                      /* 当处于连接状态并且接收到的数据不为空时将其打印出来 */
        {
            memset(g_lwip_demo_recvbuf, 0, LWIP_DEMO_RX_BUFSIZE);           /* 数据接收缓冲区清零 */

            for (q = p; q != NULL; q = q->next)                             /* 遍历完整个pbuf链表 */
            {
                /* 判断要拷贝到LWIP_DEMO_RX_BUFSIZE中的数据是否大于LWIP_DEMO_RX_BUFSIZE的剩余空间,如果大于 */
                /* 的话就只拷贝LWIP_DEMO_RX_BUFSIZE中剩余长度的数据,否则的话就拷贝所有的数据 */
                if (q->len > (LWIP_DEMO_RX_BUFSIZE - data_len)) memcpy(g_lwip_demo_recvbuf + data_len, q->payload, (LWIP_DEMO_RX_BUFSIZE - data_len)); /* 拷贝数据 */
                else memcpy(g_lwip_demo_recvbuf + data_len, q->payload, q->len);

                data_len += q->len;

                if (data_len > LWIP_DEMO_RX_BUFSIZE) break;                 /* 超出TCP客户端接收数组,跳出 */
            }

            g_lwip_send_flag |= 1 << 6;                                     /* 标记接收到数据了 */
            g_lwipdev.remoteip[0] = tpcb->remote_ip.addr & 0xff;            /* IADDR4 */
            g_lwipdev.remoteip[1] = (tpcb->remote_ip.addr >> 8) & 0xff;     /* IADDR3 */
            g_lwipdev.remoteip[2] = (tpcb->remote_ip.addr >> 16) & 0xff;    /* IADDR2 */
            g_lwipdev.remoteip[3] = (tpcb->remote_ip.addr >> 24) & 0xff;    /* IADDR1 */
            tcp_recved(tpcb, p->tot_len);                                   /* 用于获取接收数据,通知LWIP可以获取更多数据 */
            pbuf_free(p);                                                   /* 释放内存 */
            ret_err = ERR_OK;
        }
    }
    else                                                                    /* 服务器关闭了 */
    {
        tcp_recved(tpcb, p->tot_len);                                       /* 用于获取接收数据,通知LWIP可以获取更多数据 */
        es->p = NULL;
        pbuf_free(p);                                                       /* 释放内存 */
        ret_err = ERR_OK;
    }

    return ret_err;
}

/**
 * @brief       lwIP tcp_err函数的回调函数
 * @param       arg :传入的参数
 * @param       err :错误码
 * @retval      无
 */
void lwip_tcp_server_error(void *arg, err_t err)
{
    LWIP_UNUSED_ARG(err);
    printf("tcp error:%x\r\n", (uint32_t)arg);

    if (arg != NULL)mem_free(arg); /* 释放内存 */
}

/**
 * @brief       lwIP数据发送,用户应用程序调用此函数来发送数据
 * @param       tpcb :TCP控制块
 * @retval      返回值:0,成功;其他,失败
 */
err_t lwip_tcp_server_usersent(struct tcp_pcb *tpcb)
{
    err_t ret_err;
    struct tcp_server_struct *es;
    es = tpcb->callback_arg;

    if (es != NULL)                                                                         /* 连接处于空闲可以发送数据 */
    {
        es->p = pbuf_alloc(PBUF_TRANSPORT, strlen((char *)g_lwip_demo_sendbuf), PBUF_POOL); /* 申请内存 */
        pbuf_take(es->p, (char *)g_lwip_demo_sendbuf, strlen((char *)g_lwip_demo_sendbuf)); /* 将lwip_tcp_server_sentbuf[]中的数据拷贝到es->p_tx中 */
        lwip_tcp_server_senddata(tpcb, es);                                                 /* 将lwip_tcp_server_sentbuf[]里面复制给pbuf的数据发送出去 */
        g_lwip_send_flag &= ~(1 << 7);                                                      /* 清除数据发送标志 */

        if (es->p != NULL)pbuf_free(es->p);                                                 /* 释放内存 */

        ret_err = ERR_OK;
    }
    else
    {
        tcp_abort(tpcb);                                                                    /* 终止连接,删除pcb控制块 */
        ret_err = ERR_ABRT;
    }

    return ret_err;
}

测试结果: