[STM32MP1] 【STM32MP135F-DK测评】移植Libuv,建立网络服务器

[复制链接]
5331|1
 楼主| jobszheng 发表于 2024-1-29 06:52 | 显示全部楼层 |阅读模式
【STM32MP135F-DK测评】移植Libuv,建立网络服务器

在本次充电桩母桩原型设计中,核心服务之一便是网络服务器。对于子桩来说,为简化设计,节约成本,其仅保留充电控制模块,如启动序列逻辑执行,急停判断,本地局域网网络通讯模块等,即利用STM32F107等低成本MCU实现方案。而将计费,数据收集、整理,加密/解密,GUI显示等关键功能交给STM32MP135来实现。这样,对于充电场站来说,部署“1+N”模式必将节约前期投资。

基于此设计架构,STM32MP135需要对子桩提供网络服务,用于交换数据,即在C/S架构模型中,作为server的角色。在本章的实验中,我们移植libuv框架,提供TCP服务端,便于我们开发应用层程序。

我们引用一段libuv的介绍:

libuv是一个高性能的跨平台异步I/O库,它为开发者提供了一组统一的API,可以在不同的操作系统上实现高效的网络和文件传输。libuv的设计目标是提供高性能、可移植性和易用性,成为许多高性能网络和异步I/O应用程序的首选库。
libuv的设计理念是简单、高效和可扩展。它使用C语言编写,遵循简洁、易读的原则,使得开发者能够快速上手并编写高性能的异步I/O应用程序。libuv还提供了丰富的文档和示例代码,帮助开发者更好地理解和使用库的功能。

在性能方面,libuv通过使用异步I/O和事件循环模型,实现了高效的并发处理能力。它能够处理数万个并发连接,并且具有较低的延迟和较高的吞吐量。libuv还支持多种协议和传输方式,包括TCP、UDP、HTTP等,使得开发者可以根据需要选择适合的协议和传输方式。

21ic_23.png

方案确定,我们立刻开干!

先在github.com下载libuv的源代码。在交叉编译环境中重新编译即可。


21ic_22.png

我们本次使用静态库来完成测试,所以将libuv.a拷贝到我们的工程目录,同时也需要将头文件也拷贝过去,包括uv.h与uv文件夹(libuv/include)。

我们再编写TCP服务端程序,源代码如下:

  1. #include <gtk/gtk.h>
  2. #include <stdio.h>
  3. #include <stdint.h>
  4. #include "uv.h"

  5. uv_loop_t *loop;
  6. #define DEFAULT_PORT 7000

  7. #define DEFAULT_BACKLOG 128

  8. typedef struct{
  9.     uv_write_t req;
  10.     uv_buf_t buf;
  11. }write_req_t;

  12. //负责为新来的消息申请空间
  13. void alloc_buffer(uv_handle_t* handle,size_t suggested_size,uv_buf_t* buf)
  14. {
  15.     buf->len = suggested_size;
  16.     buf->base = (char *)malloc(suggested_size);
  17. }

  18. void on_close(uv_handle_t* handle)
  19. {
  20.     if(handle != NULL)
  21.         free(handle);
  22. }

  23. void free_write_req(uv_write_t *req)
  24. {
  25.     write_req_t *wr = (write_req_t*)req;

  26.     free(wr->buf.base);
  27.     free(wr);
  28. }

  29. void echo_write(uv_write_t* req, int status)
  30. {
  31.     if(status)
  32.     {
  33.         fprintf(stderr, "Write error %s\n", uv_strerror(status));
  34.     }

  35.     free_write_req(req);
  36. }

  37. //负责处理新来的消
  38. void echo_read(uv_stream_t* client,ssize_t nread,const uv_buf_t* buf)
  39. {
  40.     if(nread > 0)
  41.     {
  42.         buf->base[nread] = 0;
  43.         fprintf(stdout,"recv:%s",buf->base);

  44.         write_req_t *req = (write_req_t *)malloc(sizeof(write_req_t));
  45.         req->buf = uv_buf_init(buf->base,nread);

  46.         uv_write((uv_write_t *)req,client,&req->buf,1,echo_write);

  47.         return;
  48.     }
  49.     else if(nread < 0)
  50.     {
  51.         if(nread != UV_EOF)
  52.         {
  53.             fprintf(stderr,"Read error %s\n",uv_err_name(nread));
  54.         }
  55.         else
  56.         {
  57.             fprintf(stderr,"client disconnect\n");
  58.         }
  59.         uv_close((uv_handle_t*)client,on_close);
  60.     }

  61.     if(buf->base != NULL)
  62.     {
  63.         free(buf->base);
  64.     }
  65. }

  66. void on_new_connection(uv_stream_t* server,int status)
  67. {
  68.     if(status < 0)
  69.     {
  70.         fprintf(stderr,"New connection error %s\n",uv_strerror(status));
  71.         return;
  72.     }
  73.     uv_tcp_t *client = (uv_tcp_t *)malloc(sizeof(uv_tcp_t));
  74.     uv_tcp_init(loop,client);

  75.     if(uv_accept(server,(uv_stream_t*)client) == 0)
  76.     {
  77.         uv_read_start((uv_stream_t*)client,alloc_buffer,echo_read);
  78.     }
  79.     else
  80.     {
  81.         uv_close((uv_handle_t*) client, NULL);
  82.     }
  83. }

  84. static void
  85. print_hello (GtkWidget *widget,
  86.              gpointer   data)
  87. {
  88.   g_print ("TCP server Test \n");
  89. }

  90. static void tcp_server_init(GtkWidget *widget,
  91.              gpointer   data)
  92. {
  93.   printf("libuv version: %s\n", uv_version_string());
  94.   loop = uv_default_loop();

  95.     uv_tcp_t server;
  96.     uv_tcp_init(loop,&server);

  97.     struct sockaddr_in addr;

  98.     uv_ip4_addr("0.0.0.0",DEFAULT_PORT,&addr);

  99.     uv_tcp_bind(&server,(const struct sockaddr*)&addr,0);

  100.     int r = uv_listen((uv_stream_t*)&server,DEFAULT_BACKLOG,on_new_connection);

  101.     if(r)
  102.     {
  103.         fprintf(stderr, "Listen error %s\n", uv_strerror(r));
  104.         return 1;
  105.     }

  106.     return uv_run(loop,UV_RUN_DEFAULT);
  107. }

  108. static void
  109. activate (GtkApplication *app,
  110.           gpointer        user_data)
  111. {
  112.   GtkWidget *window;
  113.   GtkWidget *button;
  114.   GtkWidget *button_box;

  115.   window = gtk_application_window_new (app);
  116.   gtk_window_set_title (GTK_WINDOW (window), "Window");
  117.   gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);

  118.   button_box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
  119.   gtk_container_add (GTK_CONTAINER (window), button_box);

  120.   button = gtk_button_new_with_label ("libuv Demo");
  121.   g_signal_connect (button, "clicked", G_CALLBACK (tcp_server_init), NULL);
  122.   g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window);
  123.   gtk_container_add (GTK_CONTAINER (button_box), button);

  124.   gtk_widget_show_all (window);
  125. }

  126. int
  127. main (int    argc,
  128.       char **argv)
  129. {
  130.   GtkApplication *app;
  131.   int status;

  132.   app = gtk_application_new ("org.gtk.example", G_APPLICATION_DEFAULT_FLAGS);
  133.   g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
  134.   status = g_application_run (G_APPLICATION (app), argc, argv);
  135.   g_object_unref (app);

  136.   return status;
  137. }
我们在编译之后,将程序上传到STM32MP135,并运行。在windows下通过客户端软件模拟子桩连接母桩。

21ic_24.png


21ic_21.png

至此,充电桩母桩的网络服务器原型开发完成。











classroom 发表于 2024-1-29 10:25 | 显示全部楼层
又一波开发板测评贴来了
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:嵌入式技术专家
简介:热爱开源,乐于分享。在嵌入式技术领域里面,主攻通讯协议,Modbus,TCP/IP以及虚拟化和RTOS

31

主题

746

帖子

23

粉丝
快速回复 在线客服 返回列表 返回顶部