请选择 进入手机版 | 继续访问电脑版
查看: 792|回复: 1

基于MCUXpesso SDK实现TCP Client/Server

[复制链接]
  • TA的每日心情
    开心
    2024-5-17 16:33
  • 签到天数: 268 天

    [LV.8]以坛为家I

    3334

    主题

    6604

    帖子

    0

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    32478
    最后登录
    2024-5-29
    发表于 2023-3-14 09:57:00 | 显示全部楼层 |阅读模式
    基于MCUXpesso SDK实现TCP Client/Server
    一、概述
    TCP Client & Server在服务器和客户端之间建立双向连接。它是HTTP、Telnet、FTP、SSH等应用程序使用的最常见的通信模型。

    LwIP 是MCUXpresso SDK中的免费轻量级TCP/IP协议栈. 它有三个编程接口 (API):
    RAW API: 它使用事件(event)回调函数来开发应用程序。
    Netconn API: 它是一种高级的API,以来实时操作系统(RTOS)提供的服务, Netconn API 支持多线程开发
    BSD Socket API: 它依赖Netconn API, 是为了与socket兼容而开发的。
    在本文中,我将介绍如何使用LwIP Netconn API 来实现TCP client & Server。一块EVK-RT1060 作为 TCP server, 另一块EVK-RT1060 作为TCP client。它们通过以太网路由器连接,通过TCP协议进行通信。
    该例程实现一个简单功能,如果你按client板上的SW8按钮,它将toggle服务器板上的LED。
    11.png
    本文是针对LwIP和MCUXpresso SDK的初学者。

    二、硬件配置
    PHY 设置:
    该例程使用phyksz8081, 这是EVK-RT1060 开发板的默认PHY。使用 ENET port 0。
    1. /*! @brief The ENET PHY address. */
    2. #define BOARD_ENET0_PHY_ADDRESS (0x02U) /* Phy address of enet port 0. */
    3. /* Address of PHY interface. */
    4. #define EXAMPLE_PHY_ADDRESS BOARD_ENET0_PHY_ADDRESS
    5. /* MDIO operations. */
    6. #define EXAMPLE_MDIO_OPS enet_ops
    7. /* PHY operations. */
    8. #define EXAMPLE_PHY_OPS phyksz8081_ops
    9. /* ENET clock frequency. */
    10. #define EXAMPLE_CLOCK_FREQ CLOCK_GetFreq(kCLOCK_IpgClk)
    复制代码
    配置外置PHY, 在RESET之前上拉ENET_INT:
    1. GPIO_PinInit(GPIO1, 9, &gpio_config);
    2. GPIO_PinInit(GPIO1, 10, &gpio_config);
    3. /* pull up the ENET_INT before RESET. */
    4. GPIO_WritePinOutput(GPIO1, 10, 1);
    5. GPIO_WritePinOutput(GPIO1, 9, 0);
    6. delay();
    7. GPIO_WritePinOutput(GPIO1, 9, 1);
    复制代码
    MAC 设置:
    本例程中, MAC 地址用宏 configMAC_ADDR定义:
    1. /* MAC address configuration. */
    2. #define configMAC_ADDR \
    3. { \
    4. 0x02, 0x12, 0x13, 0x10, 0x15, 0x11 \
    5. }
    复制代码
    三、网络接口初始化
    为了创建一个新的网络接口, 用户必须为一个新的网络接口结构 netif 分配空间,然后调用 netifapi_netif_add:
    1. IP4_ADDR(&fsl_netif0_ipaddr, configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3);
    2. IP4_ADDR(&fsl_netif0_netmask, configNET_MASK0, configNET_MASK1, configNET_MASK2, configNET_MASK3);
    3. IP4_ADDR(&fsl_netif0_gw, configGW_ADDR0, configGW_ADDR1, configGW_ADDR2, configGW_ADDR3);

    4. netifapi_netif_add(&fsl_netif0, &fsl_netif0_ipaddr, &fsl_netif0_netmask, &fsl_netif0_gw, &fsl_enet_config0, ethernetif0_init, tcpip_input);
    复制代码
    将网络接口设置为默认接口
    1. netifapi_netif_set_default(&fsl_netif0);
    复制代码
    启动网络接口,接下来可以处理数据了。
    1. netifapi_netif_set_up(&fsl_netif0);
    复制代码
    四、LwIp初始化

    调用tcpip_init 创建一个 tcpip_thread线程, 该线程实现LwIP 核心功能. 其他线程用消息队列与lwip线程通信。
    1. tcpip_init(NULL, NULL);
    复制代码
    五、TCP Client & Server实现


    对于TCP 通信, 服务器监听所有的连接请求。当请求到达时,服务器接受它并在服务器和客户端之间传输数据。下图是一个TCP连接的建立过程。
    12.png
    在客户端建立建立TCP连接的步骤如下:
    1、使用netconn_new() 函数创建一个netconn.
    2、使用netconn_connect() 函数连接到服务器地址上。
    3、通过netconn_send() 和netconn_recv() 发送和接收数据。
    4、使用 netconn_close() 关闭连接.
    在服务器端建立TCP连接的步骤如下:
    1、使用netconn_new() 函数创建连接;
    2、使用netconn_bind() 函数将连接绑定到地址
    3、使用 netconn_listen() 函数监听连接
    4、使用 netconn_accept() 函数接受连接,这会阻塞直到客户端连接
    5、通过 netconn_send() and netconn_recv()函数发送和接收数据.
    4、使用netconn_close() 函数关闭连接
    TCP Server实现
    netconn_new() 函数创建连接:
    1. conn = netconn_new(NETCONN_TCP);
    复制代码
    netconn_bind() 函数将连接绑定到地址
    1. netconn_bind(conn, IP_ADDR_ANY, TCP_CUSTOM_PORT);
    复制代码
    netconn_listen() 函数监听连接:
    1. /* Tell connection to go into listening mode. */
    2. netconn_listen(conn);
    复制代码
    netconn_accept() 函数接受连接,这会阻塞直到客户端连接
    1. err = netconn_accept(conn, &newconn);
    复制代码
    netconn_recv() 函数用来接收数据
    netconn_send() 函数用来发送数据到远端的IP/Port.


    在该例程中, 如果服务器接收到一个 ‘TOGGLE’ 消息, 这将会toggle 一个LED. (GPIO1/3, need to connect a LED manually)
    1. while ((err = netconn_recv(newconn, &buf)) == ERR_OK) {
    2.    PRINTF("Received %s\n", buf->p->payload);
    3.    do {
    4.       netbuf_data(buf, &data, &len);
    5.       tcp_rx_buf = (void *)data;
    6.       if (tcp_rx_buf[0] == 'T')
    7.       {
    8.          PRINTF("LED was toggled from client\r\n");         GPIO_PortToggle(EXAMPLE_LED_GPIO, 1u << EXAMPLE_LED_GPIO_PIN);         netconn_write(newconn, TcpReply, sizeof(TcpReply) , NETCONN_COPY );
    9.       }
    10.    } while (netbuf_next(buf) >= 0);
    11.    netbuf_delete(buf);
    12. } //end of while(( err
    复制代码
    TCP Client实现
    netconn_new() 函数创建连接:
    1. conn = netconn_new(NETCONN_TCP);
    2. memset(&server_addr, 0, sizeof(server_addr));
    3. server_addr.sin_family = AF_INET;
    4. server_addr.sin_port = PP_HTONS(TCP_CUSTOM_PORT);
    5. server_addr.sin_addr.s_addr = server_ip_addr.addr;
    6. err = connect(client_sock, (struct sockaddr *)&server_addr, sizeof(server_addr));
    7. LWIP_ASSERT("connect fail, please start TCP server first ! ", err == 0);
    复制代码
    在该例程中,我们初始化一个GPIO, 使能一个中断。当SW8被按下时, 客户端board会发出一个’Toggle’命令给TCP server。
    1. while (1)
    2. {
    3.    if (g_InputSignal)
    4.    {
    5.       delay();
    6.       if (1 == GPIO_PinRead(EXAMPLE_SW_GPIO, EXAMPLE_SW_GPIO_PIN))
    7.       {
    8.          PRINTF("%s is turned on.\r\n", EXAMPLE_SW_NAME);
    9.          err = send(server_sock, Sendtext, sizeof(Sendtext) / sizeof(Sendtext[0]), 0);
    10.       }
    11.       /* Reset state of switch. */
    12.       g_InputSignal = false;
    13.    } //end of if (g_InputSignal)
    14. }
    复制代码


    签到签到
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2024-3-20 09:36
  • 签到天数: 451 天

    [LV.9]以坛为家II

    3

    主题

    1147

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    2341
    最后登录
    2024-5-12
    发表于 2023-3-14 10:15:52 | 显示全部楼层
    这个还是典型的应用呀
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2024-5-29 10:04 , Processed in 0.117902 second(s), 22 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表