FreeRTOS Lwip Socket APi TCP Server 1对多

news2025/1/4 19:18:26

源文件

/**
 ******************************************************************************
 * @file         lwip_tcp_driver.cpp
 * @brief        TCP Server implementation using LwIP
 ******************************************************************************
 * @attention
 * @author       by syf
 ******************************************************************************
 */

#include "lwip_tcp_driver.h"
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include <cstring> // For memset

static const char send_data[8] = {0xff,0x44,0x55,0x66,0xdd};

namespace lwip_tcp {
  
struct client_info *client_fo;
struct client_task_info *client_task_fo;
struct link_socket_info *socket_link_info;

  // 发送数据的任务
void send_task(void *param) {
    struct client_info* client = (struct client_info *)param;
    const char *data_to_send = "Hello, Client!";
    int data_length = strlen(data_to_send);
 
    while (1) {
        // 发送数据到客户端
        int sent_bytes = send(client->socket_num, data_to_send, data_length, 0);
        if (sent_bytes < 0) {
            debug_print("Failed to send data to client[%d]\r\n", client->socket_num);
            break; // 如果发送失败,退出循环
        }
        
        debug_print("Sent %d bytes to client[%d]\r\n", sent_bytes, client->socket_num);
        vTaskDelay(1000 / portTICK_PERIOD_MS); // 延迟1秒
    }
 
    // 如果退出循环,释放客户端信息并删除任务
    mem_free(client);
    closesocket(client->socket_num);
    vTaskDelete(NULL);
}
  
void tcp_server_thread(void *param){
  
    struct client_info* client = (struct client_info *)param;
    /* 某个客户端连接 */
    debug_print("Client[%d]%s:%d is connect server\r\n", client->socket_num, inet_ntoa(client->ip_addr.sin_addr),ntohs(client->ip_addr.sin_port));
    /* 向客户端发送连接成功信息 */
    send(client->socket_num, (const void* )send_data, strlen(send_data), 0);
    
     // 创建发送任务
    TaskHandle_t send_task_handle;
    xTaskCreate(send_task, "SendTask", 1024, (void *)client, osPriorityNormal, &send_task_handle);
    if (send_task_handle == NULL) {
        debug_print("Failed to create send task for client[%d]\r\n", client->socket_num);
    }
  
    while (1){
        char str[1024];
        memset(str, 0, sizeof(str));
        int bytes = recv(client->socket_num, str, sizeof(str), 0);
        
        /* 获取关闭连接的请求 */
        if (bytes <= 0){
          mem_free(client);
          closesocket(client->socket_num);
          break;
        }
        
        debug_print("[%d] %s:%d recv size:%d\r\n", client->socket_num, inet_ntoa(client->ip_addr.sin_addr),ntohs(client->ip_addr.sin_port), bytes);
        
        send((int )client->socket_num, (const void * )str, bytes, 0);
    }
    
    debug_print("[%d]%s:%d is disconnect...\r\n", client->socket_num, inet_ntoa(client->ip_addr.sin_addr),ntohs(client->ip_addr.sin_port));
    
    vTaskDelete(NULL); /* 删除该任务 */
}

void tcp_server_init(void){
    int sin_size = sizeof(struct sockaddr_in);
    char client_name[10] = "server";
    char client_num[10];
    
    /* socket连接结构体申请内存 */
    socket_link_info = (struct link_socket_info *)mem_malloc(sizeof(struct link_socket_info));
    
    /* 设置客户端任务信息 */
    client_task_fo = (struct client_task_info *)mem_malloc(sizeof(struct client_task_info));
    client_task_fo->client_handler = NULL;
    client_task_fo->client_task_pro = osPriorityNormal;
    client_task_fo->client_task_stk = 1024;  //无法运行时增大栈内存
    
    /* 创建socket连接 */
    if((socket_link_info->sock_listen = socket(AF_INET, SOCK_STREAM, 0)) == -1){
        debug_print("Socket error\r\n");
        return;
    }

    /* 初始化连接的服务端地址 */
    socket_link_info->listen_addr.sin_family = AF_INET;
    socket_link_info->listen_addr.sin_port = htons(5000);
    socket_link_info->listen_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    memset(&(socket_link_info->listen_addr.sin_zero), 0, sizeof(socket_link_info->listen_addr.sin_zero));

    /* 绑定socket和连接的服务端地址信息 */
    if (bind(socket_link_info->sock_listen, (struct sockaddr * )&socket_link_info->listen_addr, sizeof(struct sockaddr)) < 0){
        debug_print("Bind fail!\r\n");
        goto __exit;
    }

    /* 监听客户端的数量 */
    listen(socket_link_info->sock_listen, 4);
    debug_print("begin listing...\r\n");

    while (1){
        /* 请求客户端连接 */
        socket_link_info->sock_connect = accept(socket_link_info->sock_listen, (struct sockaddr* )&socket_link_info->connect_addr, (socklen_t* )&sin_size);
        
        if (socket_link_info->sock_connect == -1){
            debug_print("no socket,waitting others socket disconnect.\r\n");
            continue;
        }
        
        lwip_itoa((char *)socket_link_info->sock_connect, (size_t)client_num, 10);
        strcat(client_name, client_num);
        client_task_fo->client_name = client_name;
        client_task_fo->client_num = client_num;
        
        /* 初始化连接客户端信息 */
        client_fo = (struct client_info *)mem_malloc(sizeof(struct client_info));
        client_fo->socket_num = socket_link_info->sock_connect;
        memcpy(&client_fo->ip_addr, &socket_link_info->connect_addr, sizeof(struct sockaddr_in));
        client_fo->sockaddr_len = sin_size;
        
        /* 创建连接的客户端任务 */
        xTaskCreate((TaskFunction_t )tcp_server_thread,  
                    (const char *   )client_task_fo->client_name,
                    (uint16_t       )client_task_fo->client_task_stk,
                    (void *         )(void*) client_fo,
                    (UBaseType_t    )client_task_fo->client_task_pro ++ ,
                    (TaskHandle_t * )&client_task_fo->client_handler);
        
        if (client_task_fo->client_handler == NULL){
            debug_print("no memery for thread %s startup failed!\r\n",client_task_fo->client_name);
            mem_free(client_fo);
            continue;
        }else{
            debug_print("thread %s success!\r\n", client_task_fo->client_name);
        }
    }
    
__exit: 
    debug_print("listener failed\r\n");
    /* 关闭这个socket */
    closesocket(socket_link_info->sock_listen);
    vTaskDelete(NULL); /* 删除本任务 */
}

} // lwip_tcp namespace end

头文件

/**
  ******************************************************************************
  * @file         lwip_tcp_driver.h
  * @brief   
  ******************************************************************************
  * @attention
  * @auther       by shiyongfu
  ******************************************************************************
  */
#ifndef LWIP_TCP_DRIVER_H
#define LWIP_TCP_DRIVER_H

#include "stm32f4xx_hal.h"
#include "lwip/opt.h"
#include "lwip/sockets.h"

#include "lwip/sys.h"
#include "lwip/api.h"

namespace lwip_tcp{
  /* 客户端的信息 */
  struct client_info
  {
    int socket_num;                 /* socket号的数量 */
    struct sockaddr_in ip_addr;     /* socket客户端的IP地址 */
    int sockaddr_len;               /* socketaddr的长度 */
  };

  /* 客户端的任务信息 */
  struct client_task_info
  {
    UBaseType_t client_task_pro;    /* 客户端任务优先级 */
    uint16_t client_task_stk;       /* 客户端任务优先级 */
    TaskHandle_t * client_handler;  /* 客户端任务控制块 */
    char *client_name;              /* 客户端任务名称 */
    char *client_num;               /* 客户端任务数量 */
  };

  /* socket信息 */
  struct link_socket_info
  {
    int sock_listen;                /* 监听 */
    int sock_connect;               /* 连接 */
    struct sockaddr_in listen_addr; /* 监听地址 */
    struct sockaddr_in connect_addr;/* 连接地址 */
  };
    
    void tcp_server_init(void);
    void tcp_client_init(void);
}
#endif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2270204.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

GDB:条件断点:判断相等时使用一个等号还是两个等号

GDB&#xff1a;条件断点&#xff1a;判断相等时使用一个等号还是两个等号 这其实是一个特别简单的问题&#xff0c;网上不同的人分享的也不一样&#xff0c;有的例子用“”&#xff0c;有的例子用“”。 用最简单的helloworld来实验一下&#xff1a; #include <stdio.h&…

TypeScript 常用类型

文章目录 1. 类型注解2. 原始类型3. 数组类型4. 联合类型5. 类型别名6. 函数类型7. 对象类型8. 接口类型8.1 接口声明8.2 接口继承 9. 元组类型10. 类型断言11. 字面量类型12. 枚举类型12.1 数字枚举12.2 字符串枚举 13. any 类型14. typeof 运算符 1. 类型注解 前言&#xff1…

路由基本配置实验

路由器用于实现不同类型网络之间的互联。 路由器转发ip分组的基础是路由表。 路由表中的路由项分为直连路由项、静态路由项和动态路由项。 通过配置路由器接口的ip地址和子网掩码自动生成直连路由项。 通过手工配置创建静态路由项。 热备份路由器协议允许将由多个路由器组…

在Ubuntu 18.04.6 LTS安装OpenFace流程

修改配置:将gcc8&#xff0c;g8作为默认选项 sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-8 100 sudo update-alternatives --config gcc sudo update-alternatives --install /usr/bin/g g /usr/bin/g-8 100 sudo update-alternatives --config g 查…

通过 4 种方式快速将音乐从 iPod 传输到 Android

概括 在 iPod 上听音乐很酷&#xff0c;但是当您拥有最新的 Android 手机时&#xff0c;也许您想在新手机上欣赏 iPod 音乐。那么&#xff0c;你的计划是什么&#xff1f;如何将音乐从 iPod 传输到 Android&#xff1f; 如果您担心这个问题&#xff0c;请看看下面的方法。他们…

Golang学习历程【第五篇 复合数据类型:数组切片】

Golang学习历程【第五篇 复合数据类型&#xff1a;数组&切片】 1. 数组&#xff08;Array&#xff09;1.1 数组的定义1.2 初始化数组1.3 数据的循环遍历1.4 多维数组 2. 切片&#xff08;Slice&#xff09;2.1 切片声明、初始化2.2 基于数组创建切片2.2 切片的长度(len)和容…

PDF预览插件

PDF预览插件 可用于当前页面弹窗形式查看,可增加一些自定义功能 pdf预览插件 代码块: pdfobject.js <div class="pdfwrap"><div class="item"><h3>笑场</h3><div class="tags"><p>李诞</p><i&…

Chrome 浏览器下载安装教程,保姆级教程

大家好&#xff0c;今天我们来聊一聊如何在国内下载和安装最新版本的 Chrome 浏览器。由于众所周知的原因&#xff0c;Google 的网站在国内是被屏蔽的&#xff0c;因此很多朋友在下载 Chrome 浏览器 时会遇到困难。其实&#xff0c;不必担心&#xff0c;今天我将为大家带来一份…

Java开发 PDF文件生成方案

业务需求背景 业务端需要能够将考试答卷内容按指定格式呈现并导出为pdf格式进行存档&#xff0c;作为紧急需求插入。导出内容存在样式复杂性&#xff0c;包括特定的字体&#xff08;中文&#xff09;、字号、颜色&#xff0c;页面得有页眉、页码&#xff0c;数据需要进行表格聚…

CSS进阶和SASS

目录 一、CSS进阶 1.1、CSS变量 1.2、CSS属性值的计算过程 1.3、做杯咖啡 1.4、下划线动画 1.5、CSS中的混合模式(Blending) 二、SASS 2.1、Sass的颜色函数 2.2、Sass的扩展(extend)和占位符(%)、混合(Mixin) 2.3、Sass的数学函数 2.4、Sass的模块化开发 2.5、Sass…

GXUOJ-算法-补题:22级《算法设计与分析》第一次课堂练习

2.最大子数组和 问题描述 代码解答 #include<bits/stdc.h> using namespace std; const int N1005; int sum,n,a[N]; int res-1;int result(){for(int i0;i<n;i){if(sum<0) suma[i];else{suma[i];resmax(res,sum);}}return res; } int main(){cin>>n;for(i…

纵览!报表控件 Stimulsoft Reports、Dashboards 和 Forms 2025.1 新版本发布!

Stimulsoft 2025.1 新版发布&#xff0c;旨在增强您创建报告、仪表板和 PDF 表单的体验&#xff01;此最新版本为您带来了许多改进和新功能&#xff0c;使数据处理更加高效和用户友好。亮点包括对 .NET 9 的支持、Microsoft Analysis Services 的新数据适配器、发布向导中适用于…

Javascript-web API-day04

文章目录 01-实例化日期对象02-常见的日期对象方法03-年月日案例04-年月日简化05-得到时间戳06-倒计时07-关闭节点08-子节点09-增加节点10-克隆节点11-删除节点12-m端时间13-(swiper插件的使用)移动端轮播图游乐园项目 学成在线重构 01-实例化日期对象 <!DOCTYPE html> …

Formality:匹配(match)是如何进行的?

相关阅读Formalityhttps://blog.csdn.net/weixin_45791458/category_12841971.html?spm1001.2014.3001.5482 匹配点、对比点和逻辑锥 匹配指的是Formality工具尝试将参考设计中的每个匹配点与实现设计中的相应匹配点进行配对&#xff0c;这里的匹配点包括对比点(Compare Point…

浅谈电力监控系统在厂房电力工程中的设计与应用

安科瑞汪洋/汪小姐/汪女士---Acrelwy 摘要 &#xff1a;电力监控系统在厂房电力工程中的应用&#xff0c;稳步提升了电力系统管理的智能化、信息化水平&#xff0c;确保电力资源的合理化应用&#xff0c;满足工业生产的基本需求。为确保电力监控系统与厂房电力工程的有效结合&…

AIGC生图实战技巧分享

目录 引言 &#x1f343;安装与配置代码 &#x1f343;数据处理代码 &#x1f343;生图请求代码 引言 本文展示了 AIGC 生图相关的代码示例&#xff0c;包括安装与配置、数据处理以及生图请求等不同阶段的代码&#xff0c;清晰呈现了整个技术实现过程中代码层面的操作要点和…

Mac iTerm2集成DeepSeek AI

1. 去deepseek官网申请api key&#xff0c;DeepSeek 2. 安装iTerm2 AI Plugin插件&#xff0c;https://iterm2.com/ai-plugin.html&#xff0c;插件解压后直接放到和iTerms相同的位置&#xff0c;默认就在/Applications 下 3. 配置iTerm2 4. 重启iTerm2,使用快捷键呼出AI对话…

akamai3.0反爬教程逆向分析9个视频汇总

目录 一、akamai2.0文章二、akamai3.0每月疑似改版点二、9个视频汇总如下 一、akamai2.0文章 文章1cookie反爬之akamai_2.0-上文章2cookie反爬之akamai_2.0-上文章3cookie反爬之akamai_2.0-上文章中akamai2.0对应调试html与js文件 二、akamai3.0每月疑似改版点 详细文字与2.…

解决chatgpt(mac app登陆)出现报错:获取您的 SSO 信息时出错

由于我们是app登陆的&#xff0c;不能直接修改网站的链接&#xff0c;将 URL 的域名部分从 auth.openai.com 变更为 auth0.openai.com&#xff0c;然后加载新的地址&#xff0c;这时候应该就可以正常登录或注册了。 所以我们使用邮箱先载入auth0的地址&#xff0c;再更改自己的…

基于Springboot + vue实现的高校办公室行政事务管理系统

&#x1f942;(❁◡❁)您的点赞&#x1f44d;➕评论&#x1f4dd;➕收藏⭐是作者创作的最大动力&#x1f91e; &#x1f496;&#x1f4d5;&#x1f389;&#x1f525; 支持我&#xff1a;点赞&#x1f44d;收藏⭐️留言&#x1f4dd;欢迎留言讨论 &#x1f525;&#x1f525;&…