STM32三方库 – 网络通信/Mongoose

C/C++网络库,提供事件驱动的非阻塞 TCP、UDP、HTTP、WebSocket、MQTT等协议的API。

跨平台:

  1. 适用于 Linux/UNIX、MacOS、Windows、Android;

  2. 适用于 STM32、NXP、ESP32、NRF52、TI、Microchip 等;

  3. 只需编写一次代码,即可在任何地方使用;

  4. 适用于跨公司统一网络基础设施代码;

内置协议:TCP/UDP、SNTP、HTTP、MQTT、Websocket等;

异步 DNS 解析器

极小的静态和运行时占用空间

源代码符合 ISO C 和 ISO C++ 标准

易于集成:只需将mongoose.c和mongoose.h文件复制到源代码树中即可

内置 TCP/IP 堆栈,带有用于裸机或 RTOS 系统的驱动程序;

可以使用 BSD API 在现有的 TCP/IP 堆栈上运行,例如 lwIP、Zephyr、Azure 等;

内置 TLS 1.3 ECC 堆栈,也可以使用外部 TLS 库 – mbedTLS、OpenSSL 或其他;

不依赖任何其他软件来实现网络。

一、Mongoose软件包

1、源码下载

Github:https://github.com/cesanta/mongoose/tree/master

2、修改mongoose.h

#define MG_ARCH MG_ARCH_RTTHREAD

3、使能POSIX文件系统

二、Mongoose文档

https://mongoose.ws/documentation/#user-guide

三、Mongoose SHA

1、CRC32

char data[] = "hello";

uint32_t crc = mg_crc32(0, data, sizeof(data));

2、MD5

mg_md5_ctx ctx;

mg_md5_init(&ctx);

mg_md5_update(&ctx, "data", 4);       // hash "data" string

mg_md5_update(&ctx, "more data", 9);  // hash "more data" string

nsigned char buf[16];

mg_md5_final(&ctx, buf);              // `buf` is now MD5 hash

3、SHA1

mg_sha1_ctx ctx;mg_sha1_init(&ctx);

mg_sha1_update(&ctx, "data", 4);      // hash "data" string

mg_sha1_update(&ctx, "more data", 9); // hash "more data" string

unsigned char buf[20];

mg_sha1_final(buf, &ctx);             // `buf` is now SHA1 hash

四、Mongoose TCP

1、TCP服务端
#include <rtthread.h>
#include <rtdevice.h>
#include <drv_common.h>
#include <arpa/inet.h>
#include <netdev.h>

#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>

#include "mongoose.h"

// Callback functions
static void on_listening(void) {
    rt_kprintf("Server is listening\n");
}

static void on_accept(void) {
    rt_kprintf("Client connected\n");
}

static void on_read(struct mg_connection *c, unsigned char *data, size_t len) {
    rt_kprintf("Received data: %.*s\n", (int)len, data);
    // Echo the received data back to the client
    mg_send(c, data, len);
}

static void on_close(void) {
    rt_kprintf("Client disconnected\n");
}

static void on_error(char *ev_data) {
    rt_kprintf("Error: %s\n", ev_data);
}

// Event handler
static void event_handler(struct mg_connection *c, int ev, void *ev_data) {
    switch (ev) {
        case MG_EV_OPEN:
            if (c->is_listening) {
                on_listening();
            }
            break;
        case MG_EV_ACCEPT:
            on_accept();
            break;
        case MG_EV_READ:
            on_read(c, (unsigned char *)c->recv.buf, c->recv.len);
            c->recv.len = 0;  // Clear the buffer
            break;
        case MG_EV_CLOSE:
            on_close();
            break;
        case MG_EV_ERROR:
            on_error((char *)ev_data);
            break;
        default:
            break;
    }
}

// Main function to run the TCP server
void run_tcp_server(const char *address) {
    struct mg_mgr mgr;
    struct mg_connection *connection;

    // Initialize Mongoose manager
    mg_mgr_init(&mgr);

    // Start listening on the specified address
    connection = mg_listen(&mgr, address, event_handler, NULL);
    if (connection == NULL) {
        rt_kprintf("Failed to start listening on %s\n", address);
        mg_mgr_free(&mgr);
        return;
    }

    rt_kprintf("Server listening on %s...\n", address);

    // Main loop to poll events
    while (1) {
        mg_mgr_poll(&mgr, 1000);
    }

    // Cleanup
    mg_mgr_free(&mgr);
}

#define NETDEV_NAME "e0"

int main(void)
{
    struct netdev *netdev;
    netdev = netdev_get_by_name(NETDEV_NAME);
    if (netdev == RT_NULL) {
        rt_kprintf("network interface device %s not found!\n", NETDEV_NAME);
        return -1;
    }

    while(1) {
        if(netdev_is_link_up(netdev)) {
            run_tcp_server("192.168.0.105:6666");
        }
        rt_thread_delay(100);
    }

    return RT_EOK;
}
2、TCP客户端
#include <rtthread.h>
#include <rtdevice.h>
#include <drv_common.h>
#include <arpa/inet.h>
#include <netdev.h>

#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>

#include "mongoose.h"

// Callback functions
static void on_connected(void) {
    rt_kprintf("Connected to server\n");
}

static void on_read(struct mg_connection *c, unsigned char *data, size_t len) {
    rt_kprintf("Received data: %.*s\n", (int)len, data);
    mg_send(c, data, len);
}

static void on_close(void) {
    rt_kprintf("Connection closed\n");
}

static void on_error(char *ev_data) {
    rt_kprintf("Error: %s\n", ev_data);
}

// Event handler
static void event_handler(struct mg_connection *c, int ev, void *ev_data) {
    switch (ev) {
        case MG_EV_CONNECT:
            on_connected();
            const char *welcome_message = "Hello, server!";
            mg_send(c, welcome_message, strlen(welcome_message));
            break;
        case MG_EV_READ:
            on_read(c, (unsigned char *)c->recv.buf, c->recv.len);
            c->recv.len = 0;  // Clear the buffer
            break;
        case MG_EV_CLOSE:
            on_close();
            break;
        case MG_EV_ERROR:
            on_error((char *)ev_data);
            break;
        default:
            break;
    }
}

// Main function to run the TCP client
void run_tcp_client(const char *address) {
    struct mg_mgr mgr;
    struct mg_connection *connection;

    // Initialize Mongoose manager
    mg_mgr_init(&mgr);

    // Connect to the server
    connection = mg_connect(&mgr, address, event_handler, NULL);
    if (connection == NULL) {
        rt_kprintf("Failed to connect to %s\n", address);
        mg_mgr_free(&mgr);
        return;
    }

    rt_kprintf("Connecting to %s...\n", address);

    // Main loop to poll events
    while (1) {
        mg_mgr_poll(&mgr, 1000);
    }

    // Cleanup
    mg_mgr_free(&mgr);
}

#define NETDEV_NAME "e0"

int main(void)
{
    struct netdev *netdev;
    netdev = netdev_get_by_name(NETDEV_NAME);
    if (netdev == RT_NULL) {
        rt_kprintf("network interface device %s not found!\n", NETDEV_NAME);
        return -1;
    }

    while(1) {
        if(netdev_is_link_up(netdev)) {
            run_tcp_client("192.168.0.108:6666");
        }
        rt_thread_delay(100);
    }

    return RT_EOK;
}

五、Mongoose MQTT

1、MQTT客户端
#include <rtthread.h>
#include <rtdevice.h>
#include <drv_common.h>
#include <arpa/inet.h>
#include <netdev.h>

#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>

#include "mongoose.h"

static const char *s_url = "192.168.0.128:1883";
static const char *s_sub_topic = "mg/+/test";     // Subscribe topic
static const char *s_pub_topic = "mg/clnt/test";  // Publish topic
static int s_qos = 0;                             // MQTT QoS

// MQTT event callback
static void mqtt_event_handler(struct mg_connection *c, int ev, void *ev_data) {
    struct mg_mqtt_message *msg = (struct mg_mqtt_message *)ev_data;

    switch (ev) {
        case MG_EV_MQTT_OPEN:
            rt_kprintf(("%lu CONNECTED to %s", c->id, s_url));

            // Subscribe to a topic after connection
            struct mg_str subt = mg_str(s_sub_topic);
            struct mg_mqtt_opts sub_opts;
            memset(&sub_opts, 0, sizeof(sub_opts));
            sub_opts.topic = subt;
            sub_opts.qos = s_qos;
            mg_mqtt_sub(c, &sub_opts);
            rt_kprintf(("%lu SUBSCRIBED to %.*s", c->id, (int) subt.len, subt.buf));

            // Publish a message
            struct mg_str pubt = mg_str(s_pub_topic), data = mg_str("hello");
            struct mg_mqtt_opts pub_opts;
            memset(&pub_opts, 0, sizeof(pub_opts));
            pub_opts.topic = pubt;
            pub_opts.message = data;
            pub_opts.qos = s_qos;
            pub_opts.retain = false;
            mg_mqtt_pub(c, &pub_opts);
            rt_kprintf(("%lu PUBLISHED %.*s -> %.*s", c->id, (int) data.len, data.buf,
                    (int) pubt.len, pubt.buf));
            break;
        case MG_EV_MQTT_MSG:
            rt_kprintf("Received MQTT message on topic '%.*s': %.*s\n",
                       (int)msg->topic.len, msg->topic.buf,
                       (int)msg->data.len, msg->data.buf);
            break;
        case MG_EV_CLOSE:
            rt_kprintf("MQTT connection closed\n");
            break;
        case MG_EV_ERROR:
            rt_kprintf("MQTT connection error\n");
            break;
        default:
            break;
    }
}

// Main function to run the MQTT client
void run_mqtt_client(const char *mqtt_server, const char *mqtt_client_id,
                     const char *mqtt_user, const char *mqtt_pass) {
    struct mg_mgr mgr;
    struct mg_connection *mqtt_conn;

    // Initialize Mongoose manager
    mg_mgr_init(&mgr);

    // MQTT client options
    struct mg_mqtt_opts mqtt_opts;
    memset(&mqtt_opts, 0, sizeof(mqtt_opts));
    mqtt_opts.client_id = mg_str(mqtt_client_id);
    mqtt_opts.keepalive = 60;
    mqtt_opts.qos = s_qos;
    mqtt_opts.user = mg_str(mqtt_user);
    mqtt_opts.pass = mg_str(mqtt_pass);

    // Connect to MQTT broker
    mqtt_conn = mg_mqtt_connect(&mgr, mqtt_server, &mqtt_opts, mqtt_event_handler, NULL);
    if (mqtt_conn == NULL) {
        rt_kprintf("Failed to connect to MQTT broker\n");
        mg_mgr_free(&mgr);
        return;
    }

    rt_kprintf("Connecting to MQTT broker...\n");

    // Main loop to handle MQTT events
    while (1) {
        mg_mgr_poll(&mgr, 1000);
    }

    // Cleanup
    mg_mgr_free(&mgr);
}

#define NETDEV_NAME "e0"

int main(void)
{
    struct netdev *netdev;
    netdev = netdev_get_by_name(NETDEV_NAME);
    if (netdev == RT_NULL) {
        rt_kprintf("network interface device %s not found!\n", NETDEV_NAME);
        return -1;
    }

    while(1) {
        if(netdev_is_link_up(netdev)) {
            run_mqtt_client(s_url, "rtthread_client", "root", "dxf124213");
        }
        rt_thread_delay(100);
    }

    return RT_EOK;
}

作者:Xiangfu DING

物联沃分享整理
物联沃-IOTWORD物联网 » STM32三方库 – 网络通信/Mongoose

发表回复