美文网首页物联网相关技术研究物联网loT从业者
ESP8266学习笔记(5)——TCP/UDP接口使用

ESP8266学习笔记(5)——TCP/UDP接口使用

作者: Leung_ManWah | 来源:发表于2018-11-20 15:23 被阅读2次

    一、TCP与UDP优缺点

    1、TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接。

    2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付。
    TCP通过校验和,重传控制,序号标识,滑动窗口、确认应答实现可靠传输。如丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制。

    3、UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信。

    4、每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信。

    5、TCP对系统资源要求较多,UDP对系统资源要求较少。

    二、TCP客户端

    注意:充当TCP客户端,必须要知道服务端的IP地址。

    Step 1) 包含头文件

    #include "osapi.h"
    #include "user_interface.h"
    #include "espconn.h"
    #include "mem.h"
    

    Step 2) 定义一个TCP连接结构体

    struct espconn tcp_client_conn;
    

    Step 3) 定义TCP客户端初始化函数

    /**
     @brief 初始化TCP客户端
     @param remote_port 远程端口
     @return 无
    */
    void ICACHE_FLASH_ATTR
    user_tcpclient_init(uint32 remote_port)
    {
        // 1. 定义相关结构体
        struct ip_info local_info;                                  //  定义一个用于存放本地IP信息的结构体
        struct ip_addr remote_ip;                                   //  定义一个用于存放远程IP地址的结构体
    
        // 2.配置TCP客户端相关参数
        char remote_ipbuffer[32] = "192.168.100.1";
        remote_ip.addr = ipaddr_addr(remote_ipbuffer);              // 点分十进制写入IP结构体
    
        tcp_client_conn.type = ESPCONN_TCP;                        // 设置类型为TCP协议
        tcp_client_conn.state = ESPCONN_NONE;                      // 设置为无连接状态
        tcp_client_conn.proto.tcp = (esp_tcp *) os_zalloc(sizeof(esp_tcp));  
    
        wifi_get_ip_info(STATION_IF, &info);                       // 查询连接路由器后分配的IP地址
        os_memcpy(tcp_client_conn.proto.tcp->local_ip, &local_info.ip, 4);  // 设置本地IP地址
        os_memcpy(tcp_client_conn.proto.tcp->remote_ip, &remote_ip, 4);     // 设置远程IP地址
    
        tcp_client_conn.proto.tcp->local_port = espconn_port(); // 获取可用端口作为本地端口
        tcp_client_conn.proto.tcp->remote_port = remote_port;      // 设置远程端口
    
        // 3.注册连接成功和重连的回调函数
        espconn_regist_connectcb(&tcp_client_conn, tcp_client_connect_cb);
        espconn_regist_reconcb(&tcp_client_conn, tcp_client_recon_cb);
    
        // 4.连接服务器
        espconn_connect(&tcp_client_conn);
    }
    

    Step 4) 定义相关回调函数

    /**
     @brief 成功连接到服务器的回调函数
     @param arg 指向传入参数的指针
     @return 无
    */
    LOCAL void ICACHE_FLASH_ATTR
    tcp_client_connect_cb(void *arg)
    {
        struct espconn *pespconn = arg;
        espconn_regist_recvcb(pespconn, tcp_client_recv_cb);        // 注册接收回调函数
        espconn_regist_sentcb(pespconn, tcp_client_send_cb);        // 注册发送回调函数
        espconn_regist_disconcb(pespconn, tcp_client_discon_cb);    // 注册断连回调函数
        espconn_sent(pespconn, "8226", strlen("8226"));             // 发送消息  
    }
    
    /**
     @brief 连接失败的回调函数
     @param arg 指向传入参数的指针
     @param err 为错误代码
     @return 无
    */
    LOCAL void ICACHE_FLASH_ATTR
    tcp_client_recon_cb(void *arg, sint8 err)
    {
        os_printf("tcpclient connect error, error number:%d\r\n", err);
        espconn_connect((struct espconn *) arg);                   // 连接服务器
    }
    
    /**
     @brief 成功接收到服务器返回数据的回调函数
     @param arg 指向传入参数的指针
     @param pdata 字符串数组
     @param len 字符串数组长度
     @return 无
    */
    LOCAL void ICACHE_FLASH_ATTR
    tcp_client_recv_cb(void *arg, char *pdata, unsigned short len)
    {
        os_printf("tcpclient_recvdata:\t%s\n", pdata);
    }
    
    /**
     @brief 发送数据到服务器成功的回调函数
     @param arg 指向传入参数的指针
     @return 无
    */
    LOCAL void ICACHE_FLASH_ATTR
    tcp_client_send_cb(void *arg)
    {
        os_printf("tcpclient_send succeed!\n");
    }
    
    /**
     @brief 断开服务器成功的回调函数
     @param arg 指向传入参数的指针
     @return 无
    */
    LOCAL void ICACHE_FLASH_ATTR
    tcp_client_discon_cb(void *arg)
    {
        os_printf("tcpclient_disconnect!\n");
    }
    

    三、TCP服务端

    注意:充当服务端时候,要自身开启WIFI热点,等待设备接入,好比一个网关。

    Step 1) 包含头文件

    #include "osapi.h"
    #include "user_interface.h"
    #include "espconn.h"
    #include "mem.h"
    

    Step 2) 定义一个TCP连接结构体

    struct espconn tcp_server_conn;
    

    Step 3) 定义TCP服务端初始化函数

    /**
     @brief 初始化TCP服务端
     @param local_port 本地端口
     @return 无
    */
    void ICACHE_FLASH_ATTR
    user_tcpserver_init(uint32 local_port)
    {
        // 1.配置TCP服务端相关参数
        tcp_server_conn.type = ESPCONN_TCP;                        // 设置类型为TCP协议
        tcp_server_conn.state = ESPCONN_NONE;                      // 设置为无连接状态
        tcp_server_conn.proto.tcp = (esp_tcp *) os_zalloc(sizeof(esp_tcp));  
    
        tcp_server_conn.proto.tcp->local_port = local_port;        // 设置本地端口
    
        // 2.注册监听成功和重连的回调函数
        espconn_regist_connectcb(&tcp_server_conn, tcp_server_listen_cb);
        espconn_regist_reconcb(&tcp_server_conn, tcp_server_recon_cb);
    
        // 3.开始监听
        espconn_accept(&tcp_server_conn);                          // 创建 TCP server,建立监听
        espconn_regist_time(&tcp_server_conn, 180, 0);             // 设置超时断开时间 单位:秒,最大值:7200 秒
    }
    

    Step 4) 定义相关回调函数

    /**
     @brief 成功连接到客户端的回调函数
     @param arg 指向传入参数的指针
     @return 无
    */
    LOCAL void ICACHE_FLASH_ATTR
    tcp_server_listen_cb(void *arg)
    {
        struct espconn *pespconn = arg;
        espconn_regist_recvcb(pespconn, tcp_server_recv_cb);        // 注册接收回调函数
        espconn_regist_sentcb(pespconn, tcp_server_send_cb);        // 注册发送回调函数
        espconn_regist_disconcb(pespconn, tcp_server_discon_cb);    // 注册断连回调函数
    }
    
    /**
     @brief 连接失败的回调函数
     @param arg 指向传入参数的指针
     @param err 为错误代码
     @return 无
    */
    LOCAL void ICACHE_FLASH_ATTR
    tcp_server_recon_cb(void *arg, sint8 err)
    {
        os_printf("tcpserver connect error, error number:%d\r\n", err);
    }
    
    /**
     @brief 成功接收到客户端发来数据的回调函数
     @param arg 指向传入参数的指针
     @param pdata 字符串数组
     @param len 字符串数组长度
     @return 无
    */
    LOCAL void ICACHE_FLASH_ATTR
    tcp_server_recv_cb(void *arg, char *pdata, unsigned short len)
    {
        os_printf("tcpserver_recvdata:\t%s\n", pdata);
        espconn_sent((struct espconn *) arg, "this is 8266", strlen("this is 8266"));  // 发送消息
    }
    
    /**
     @brief 发送数据成功的回调函数
     @param arg 指向传入参数的指针
     @return 无
    */
    LOCAL void ICACHE_FLASH_ATTR
    tcp_server_send_cb(void *arg)
    {
        os_printf("tcpserver_send succeed!\n");
    }
    
    /**
     @brief 断开连接成功的回调函数
     @param arg 指向传入参数的指针
     @return 无
    */
    LOCAL void ICACHE_FLASH_ATTR
    tcp_server_discon_cb(void *arg)
    {
        os_printf("tcpserver_disconnect!\n");
    }
    

    四、UDP客户端

    注意:充当客户端时候,可用于广播消息。

    Step 1) 包含头文件

    #include "osapi.h"
    #include "user_interface.h"
    #include "espconn.h"
    #include "mem.h"
    

    Step 2) 定义一个UDP连接结构体

    struct espconn udp_client_conn;
    

    Step 3) 定义UDP客户端初始化函数

    /**
     @brief 初始化UDP客户端
     @param remote_port 远程端口
     @return 无
    */
    void ICACHE_FLASH_ATTR
    user_udpclient_init(uint32 remote_port)
    {
        // 1. 定义相关结构体和变量
        struct ip_info ipconfig;                                   //  定义一个用于存放IP信息的结构体
        const char udp_remote_ip[4] = {0};                         //  定义一个用于存放远端IP地址的字符串数组
    
        // 2.设置广播模式
        wifi_set_broadcast_if(STATION_MODE);                       // 仅在sta模式udp广播
    
        // 3.配置UDP客户端相关参数
        udp_client_conn.type = ESPCONN_UDP;                        // 设置类型为UDP协议
        udp_client_conn.proto.udp = (esp_udp *) os_zalloc(sizeof(esp_udp));  
    
        udp_client_conn.proto.udp->local_port = espconn_port();    // 获取可用端口作为本地端口
        udp_client_conn.proto.udp->remote_port = remote_port;      // 设置远程端口
    
        wifi_get_ip_info(STATION_IF, &ipconfig);                   // 查询连接路由器后分配的IP地址
        udp_remote_ip[4] = { 192, 168, ip4_addr3(&ipconfig.ip), 255 };  // 目标IP地址(广播)
        os_memcpy(udp_client_conn.proto.udp->remote_ip, udp_remote_ip, 4);
    
        // 4.注册发送和接收的回调函数
        espconn_regist_sentcb(&udp_client_conn, udp_client_send_cb);
        espconn_regist_recvcb(&udp_client_conn, udp_client_recv_cb);
    
        // 5.建立UDP传输    
        espconn_connect(&udp_client_conn);
    
        // 6.发送消息   
        espconn_sent(&udp_client_conn, "8266", strlen("8266"));
    }
    

    Step 4) 定义相关回调函数

    /**
     @brief 成功接收到服务端返回数据的回调函数
     @param arg 指向传入参数的指针
     @param pdata 字符串数组
     @param len 字符串数组长度
     @return 无
    */
    LOCAL void ICACHE_FLASH_ATTR
    udp_client_recv_cb(void *arg, char *pdata, unsigned short len)
    {
        os_printf("udpclient_recvdata:\t%s\n", pdata);
    }
    
    /**
     @brief 发送数据到服务端成功的回调函数
     @param arg 指向传入参数的指针
     @return 无
    */
    LOCAL void ICACHE_FLASH_ATTR
    udp_client_send_cb(void *arg)
    {
        os_printf("udpclient_send succeed!\n");
    }
    

    五、UDP服务端

    注意:充当UDP服务端时候,要自身开启WIFI热点,等待设备接入,好比一个网关。

    Step 1) 包含头文件

    #include "osapi.h"
    #include "user_interface.h"
    #include "espconn.h"
    #include "mem.h"
    

    Step 2) 定义一个UDP连接结构体

    struct espconn udp_server_conn;
    

    Step 3) 定义UDP服务端初始化函数

    /**
     @brief 初始化UDP服务端
     @param local_port 本地端口
     @param remote_port 远程端口
     @return 无
    */
    void ICACHE_FLASH_ATTR
    user_udpserver_init(uint32 local_port, uint32 remote_port)
    {
        // 1.配置UDP服务端相关参数
        udp_server_conn.type = ESPCONN_UDP;                        // 设置类型为UDP协议
        udp_server_conn.proto.udp = (esp_udp *) os_zalloc(sizeof(esp_udp));  
    
        udp_server_conn.proto.udp->local_port = local_port;        // 设置本地端口
        udp_server_conn.proto.udp->remote_port = remote_port;      // 设置远程端口
    
        // 2.注册发送和接收的回调函数
        espconn_regist_sentcb(&udp_server_conn, udp_server_send_cb);
        espconn_regist_recvcb(&udp_server_conn, udp_server_recv_cb);
    
        // 3.建立UDP传输    
        espconn_connect(&udp_server_conn);
    }
    

    Step 4) 定义相关回调函数

    /**
     @brief 成功接收到客户端返回数据的回调函数
     @param arg 指向传入参数的指针
     @param pdata 字符串数组
     @param len 字符串数组长度
     @return 无
    */
    LOCAL void ICACHE_FLASH_ATTR
    udp_server_recv_cb(void *arg, char *pdata, unsigned short len)
    {
        os_printf("udpserver_recvdata:\t%s\n", pdata);
        espconn_sent((struct espconn *) arg, "this is 8266", strlen("this is 8266"));  // 发送消息
    }
    
    /**
     @brief 发送数据到客户端成功的回调函数
     @param arg 指向传入参数的指针
     @return 无
    */
    LOCAL void ICACHE_FLASH_ATTR
    udp_server_send_cb(void *arg)
    {
        os_printf("udpserver_send succeed!\n");
    }
    

    • 由 Leung 写于 2018 年 11 月 20 日

    • 参考:[ESP8266 Non-OS SDK API参考]
        Esp8266学习之旅⑧ 你要找的8266作为UDP、TCP客户端或服务端的角色通讯,都在这了

    相关文章

      网友评论

        本文标题:ESP8266学习笔记(5)——TCP/UDP接口使用

        本文链接:https://www.haomeiwen.com/subject/fcrtqqtx.html