当前位置: 首页 > article >正文

嵌入式八股RTOS与Linux---网络系统篇

前言

  关于计网的什么TCP三次握手 几层模型啊TCP报文啥的不在这里讲,会单独分成一个计算机网络模块
  这里主要介绍介绍lwip和socket

FreeRTOS下的网络接口–移植LWIP

   实际上FreeRTOS并不自带网络接口,我们一般会通过移植lwip协议栈让FreeRTOS可以通过网络接口收发数据,具体可看博客:
一文带你掌握LWIP

  1. LWIP是什么
      LWIP是一个在嵌入式领域应用的TCP/IP协议栈,除了TCP/IP外还能支持DNS,DHCP等应用。LWIP只需要十几KB的RAM和几十KB的ROM就能使用了
  2. 如何在RTOS移植LWIP
       移植lwip前 结合着OSI模型先来说说LWIP帮我们做了哪些工作
       当我们的应用想要发起数据传输的时候,LWIP帮我们完成了TCP报文封装(传输层)–>IP报文封装(网络层)–>IP地址找到MAC地址以及对应封装(APR协议–数据链路层) 我们需要做的就是把这个层层封装好的报文(p_buf链表)通过我们实现的网络驱动接口发送出去
    在这里插入图片描述
  • step1 :编写 sys_arch.c文件
      首先我们的lwip在OS下至少需要三种东西:消息邮箱/信号量/线程创建
         可是问题是,如果我用FreeRTOS,这三东西是这些API,我用UCOSIII又是一套API,这可怎么办呢? 那lwip就把这些所有需要的操作抽象出来,然后根据不同的RTOS环境填空就好,这就是sys_arch.c做的工作,我们要去自己写sys_arch的API
err_t
sys_mutex_new(sys_mutex_t *mutex)
{LWIP_ASSERT("mutex != NULL", mutex != NULL);mutex->mut = xSemaphoreCreateRecursiveMutex();if(mutex->mut == NULL) {SYS_STATS_INC(mutex.err);return ERR_MEM;}SYS_STATS_INC_USED(mutex);return ERR_OK;
}
void
sys_mutex_lock(sys_mutex_t *mutex)
{BaseType_t ret;LWIP_ASSERT("mutex != NULL", mutex != NULL);LWIP_ASSERT("mutex->mut != NULL", mutex->mut != NULL);ret = xSemaphoreTakeRecursive(mutex->mut, portMAX_DELAY);LWIP_ASSERT("failed to take the mutex", ret == pdTRUE);
}
err_t
sys_sem_new(sys_sem_t *sem, u8_t initial_count)
{LWIP_ASSERT("sem != NULL", sem != NULL);LWIP_ASSERT("initial_count invalid (not 0 or 1)",(initial_count == 0) || (initial_count == 1));sem->sem = xSemaphoreCreateBinary();if(sem->sem == NULL) {SYS_STATS_INC(sem.err);return ERR_MEM;}SYS_STATS_INC_USED(sem);if(initial_count == 1) {BaseType_t ret = xSemaphoreGive(sem->sem);LWIP_ASSERT("sys_sem_new: initial give failed", ret == pdTRUE);}return ERR_OK;
}
  • step2: 实现底层网卡驱动程序
    这个就得我们根据硬件自己编写了
  • step3: 分配/设置/注册一个netif结构体
    netif结构体是吧我们的网卡驱动程序和lwip链接起来的关键,netif结构体中包括数据的发送函数等
    struct netif {struct netif *next;		// 以链表形式方便管理ip_addr_t ip_addr;		// 本地ip地址ip_addr_t netmask;		// 子网掩码ip_addr_t gw;				// 网关netif_output_fn output;  			// 供IP层封装完成后调用 一般就用 etharp_output()netif_linkoutput_fn linkoutput;	// ethernet_output()结束封装包后调用, 用于发送数据包netif_input_fn input;				// 用于向上层协议提交数据包// 以下是各种call_back没用上 直接不展示了netif_status_callback_fn status_callback;.....u16_t mtu;							// 最大传输字节 mtu = 1500一般u8_t hwaddr[NETIF_MAX_HWADDR_LEN];	// mac地址u8_t hwaddr_len;						// mac地址长度u8_t flags;							// 网卡的状态void * state;							// 私有数据 看自己怎么用
    };
    

  我们需要配置好这些参数的内容 然后通过netif_setup来使能这个网卡
     为什么会有多个netif?–IP协议会根据ip_route函数去找到最合适的netif把数据发送出去,不过一般来说只有一个网卡啦
具体如何初始化这个网卡的,可以看我上面提到的博客

  • step4: 初始化LWIP的核心线程
    tcpip_init()函数
  • step5: 配置lwip协议栈 lwip的参数(lwipopts.h )
  1. LWIP数据接收/发送过程?
    在这里插入图片描述

接收过程: 底层网卡通过DMA/中断收到数据–>把数据转成p_buf结构体–>调用netif->input提交给上层协议栈–>LWIP的核心线程会来处理这个数据的
发送过程: 应用层发起操作–>TCP协议封包–>IP协议封包并找到最合适的netif结构体–>ARP协议封包–>底层网卡驱动把数据发送输出
4. LWIP参数配置?–lwipopts.h
根据自己的实际需求去配置了
比如是否启用哪些协议 / 堆栈内存的大小 / 是否需要硬件校验
5. LWIP的几种API
LWIP有RAW API / NETCOON API / SOCKET API三种
在这里插入图片描述

  1. LWIP的内存管理?
      LWIP提供了两种内存管理方式: 堆内存管理和内存池内存管理 这俩中内存管理方式是可以共存的,也可以强行只用一种—(忽略标准库的malloc和free)
    内存池的使用范围:固定大小的场景,比如TCP/IP的首部用内存池就更快
    在这里插入图片描述

    • 内存池的定义:实际上就是一个大数组–通过DECRLAR宏定义
      在这里插入图片描述

    堆内存管理的使用: 灵活的大小,比如我们的数据包大小就是不确定的 通过堆内存管理算法分配–

    • 内存堆的定义:实际上也是一个大数组–通过DECRLAR宏定义
      在这里插入图片描述

    • 如何两者都启用(默认就是)?或者只启用一种
      在这里插入图片描述

Linux下的网络接口–Socket

  1. 请说一下socket网络编程中客户端和服务端用到哪些函数?
    • TCP服务器(Server)
      1. 使用函数socket()创建一个socket
      int socket(int domain, int type, int protocol);
      
      1. 设置端口复用(可选):允许多个进程或线程共享同一端口号进行通信的技术 — 提高服务器并发能力,防止端口资源耗尽
      2. 使用函数bind()绑定IP地址,端口等信息到socket上,设置全通规则
          struct sockaddr_in serv_addr;serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(8080);serv_addr.sin_addr.s_addr = INADDR_ANY;bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); // 绑定IP地址和端口号
      
      1. 使用函数listen()设置监听,使用函数accept()接收客户端上来的连接
      int listen(int sockfd, int backlog);  //backlog等待队列的长度
      
      1. 使用函数send()和recv(),或者read()和write()收发数据
      ssize_t send(int sockfd, const void *buf, size_t len, int flags);
      ssize_t recv(int sockfd, void *buf, size_t len, int flags);
      
      1. 关闭网络连接
    • TCP客户端(Client)
      1. 使用函数socket()创建一个socket
      2. 使用函数connect()连接服务器
      int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
      
      1. 使用函数send()和recv(),或者read()和write()收发数据
      2. 关闭网络连接
        UDP是基于无连接的协议,发送数据时不需要先建立连接,而是直接把数据发送过去
    • UDP服务器(Server)
      1. 使用函数socket()创建一个socket
      2. 使用函数bind() 绑定IP地址、端口等信息到socket上
      3. 收发数据,用函数recvfrom(),sendto()
      ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
      ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
      
      1. 关闭网络连接close()
    • UDP客户端(Client)
      1. 使用函数socket()创建一个socket
      2. 使用函数recvfrom(),sendto()收发数据
      3. 关闭网络连接close()
  2. 网络字节序是大小端?
  • 大端字节序(Big Endian):最高有效位存于最低内存地址处,最低有效位存于最高内存处;
  • 小端字节序(Little Endian):最高有效位存于最高内存地址,最低有效位存于最低内存处
    在这里插入图片描述

网络字节序时大端字节序
//将主机字节序转换为网络字节序
unit32_t htonl (unit32_t hostlong);
unit16_t htons (unit16_t hostshort);
//将网络字节序转换为主机字节序
unit32_t ntohl (unit32_t netlong);
unit16_t ntohs (unit16_t netshort);

  • 为什么在数据结构 struct sockaddr_in 中, sin_addr 和 sin_port 需要转换为网络字节顺序,而sin_family 需不需要呢?
    sin_addr 和 sin_port 分别封装在包的 IP 和 UDP 层。因此,它们必须要 是网络字节顺序。但是 sin_family 域只是被内核 (kernel) 使用来决定在数 据结构中包含什么类型的地址,所以它必须是本机字节顺序。同时, sin_family 没有发送到网络上,它们可以是本机字节顺序

3 Socket的阻塞和非阻塞模式

  • 阻塞模式
    调用 send()/recv() 时,若数据未就绪或缓冲区满,线程会挂起,直到操作完成
  • 非阻塞模式
    调用 send()/recv() 立即返回,通过错误码(如 EWOULDBLOCK)通知需重试
    需配合 ​I/O 多路复用​(如 select()/poll()/epoll)实现高效事件驱动
    • 非阻塞下的Socket
      在非阻塞模式下,connect() 会立即返回 EINPROGRESS(而不会等三次握手完成再返回),此时需通过 select/poll 监听 Socket 的可写事件,再通过 getsockopt(SO_ERROR) 检查连接是否成功。关键点包括:严格错误检查、超时控制、与非阻塞 IO 的协同处理

相关文章:

嵌入式八股RTOS与Linux---网络系统篇

前言 关于计网的什么TCP三次握手 几层模型啊TCP报文啥的不在这里讲,会单独分成一个计算机网络模块   这里主要介绍介绍lwip和socket FreeRTOS下的网络接口–移植LWIP 实际上FreeRTOS并不自带网络接口,我们一般会通过移植lwip协议栈让FreeRTOS可以通过网络接口收发数据,具体可…...

Django 生成 ssl 安全证书,切换 https、wss协议(daphne 、nginx)

Django 普通 http 协议不够安全,无法支持连接本地摄像头(虽然在本地 localhost 上能连),此时需要切换成 https 协议(先提个醒,我这个方法最后失败了,不过对您应该也有帮助) 目录 配置…...

告别Win10强制更新:永久关闭系统更新指南

你是否厌倦了Win10在开关机时的强制自动更新?无论你是在赶时间还是专注于工作,那突如其来的更新提示总是让人不胜其烦。屏幕上那句“正在更新,请勿关闭电源”的提示,仿佛是对你无奈的嘲笑。别担心,今天我将教你如何永久…...

【django】2-1 (django配置) 应用配置、中间件配置、模板配置

文章目录 1 基本设置2 应用配置2.1 django核心应用2.2 常用第三方应用 3 中间件3.1 默认使用的中间件3.2 其它内置中间件3.3 第三方中间件3.4 中间件的执行顺序 4 模板引擎配置4.1 配置字典的键4.2 上下文处理器 创建django项目后,会自动生成初始的项目文件如下&…...

nginx-rtmp-module之ngx_rtmp.c代码详解

1. ngx_rtmp.c — RTMP模块的主逻辑实现 这个文件是 RTMP 模块的核心,包含了 RTMP 协议模块的初始化、配置解析和服务端口的管理等功能。它的主要职责是处理 RTMP 配置、初始化模块、配置事件、初始化 RTMP 端口等。 主要功能和逻辑: 模块初始化 (ngx_…...

罗杰斯特回归

定义 逻辑回归其实就是原来的线性回归加了激活函数,这个函数其实就是sigmoid函数,把一个回归的连续数值压缩到了0到1的空间,其实只要有函数能够满足把数值压缩到0,1之间就可以(因为0到1之间的数值就是概率值) 对于分类…...

Android 10.0 SystemUI状态栏去掉刘海屏功能实现

1.前言 在android10.0的系统rom定制化开发中,在一些产品中,对于带有刘海屏的产品中,会因为 刘海屏导致状态栏能显示图片的位置很小,然后会出现状态栏图标显示为白点的功能, 接下来看下问题怎么解决 2.SystemUI状态栏去掉刘海屏功能实现的核心类 frameworks/base/core/r…...

三维空间中点、线、面的关系

三维空间中点、线、面的关系 点相对于平面的位置关系直线相对于平面的位置关系1.根据三点计算平面方程 //根据3点计算平面方程#include <iostream> #include <cmath> #include <vector>...

【嵌入式学习2】C语言 - VScode环境搭建

目录 ## 语言分类 ## c语言编译器 ## VScode相关配置 ## 语言分类 编译型语言&#xff1a;C&#xff0c;C解释型语言&#xff1a;python&#xff0c;JS ## c语言编译器 分类GCC 系列MinGWCygwinMSVC系列一套编程语言编译器将GCC编译器和GNU Binutils移植到Win32平台下的产物…...

TCP/IP的网络连接设备

TCP/IP层物理层网卡、集线器、中继器数据链路层网桥、交换机网络层路由器传输层网关应用层 1.网桥&#xff1a;网桥主要功能是将一个网络的数据沿通信线路复制到另一个网络中去&#xff0c;可以有效的连接两个局域网 2.网关&#xff1a;网关又称协议转换器&#xff0c;是将两…...

蓝桥杯真题 2109.统计子矩阵

原题地址:1.统计子矩阵 - 蓝桥云课 问题描述 给定一个 NMNM 的矩阵 AA, 请你统计有多少个子矩阵 (最小 1111, 最大 NM)NM) 满足子矩阵中所有数的和不超过给定的整数 KK ? 输入格式 第一行包含三个整数 N,MN,M 和 KK. 之后 NN 行每行包含 MM 个整数, 代表矩阵 AA. 输出格…...

利用脚本和Shader制作屏幕后处理效果

一、屏幕后处理的实现原理 该屏幕后处理的原理是将渲染完成后的屏幕纹理通过脚本和Shader完成一些操作&#xff0c;然后实现各种屏幕效果 而实现屏幕后处理效果的主要操作就是获得当下渲染完成后的屏幕图像&#xff0c;其中unity提供了一个函数用于获取此图像——OnRenderIma…...

【银河麒麟系统常识】命令:uname -m(查看系统架构)

命令&#xff1a; uname -m 功能 常用的 Linux/Unix 终端命令&#xff0c;用于显示当前系统的硬件架构&#xff1b; 返回 返回系统的CPU架构类型&#xff0c;用于判断软件兼容性&#xff1b; 输出结果架构说明常见设备x86_64Intel/AMD 64位 CPU主流 PC、服务器aarch64ARM 64位 …...

3.1.2 内存池

文章目录 3.1.2 内存池1. 什么是内存池2. 内存管理1. 定长2. 不定长3. jemalloc4. tcmalloc 3.1.2 内存池 1. 什么是内存池 内存池&#xff08;Memory Pool&#xff09; 是一种 预先分配 一块大内存&#xff0c;然后按需分配和回收 其中小块内存的技术。它的本质是管理一块连续…...

基于SpringBoot + Vue 的餐厅点餐管理系统

SpringBootVue餐厅点餐管理系统 技术框架 后端&#xff1a;springboot mybatisPlus前端&#xff1a;Vue2 elementUI数据库&#xff1a;mysql项目构建工具&#xff1a;maven 数据库表 14张 角色及功能 管理员&#xff1a;登录、用户管理、餐桌信息管理、菜品类型管理、菜…...

Android开发BasePagerAdapter

Android开发BasePagerAdapter 有个基类的PagerAdapter 方便很多 public class BasePagerAdapter extends FragmentPagerAdapter {private static final String TAG "FragmentPagerAdapter";private static final boolean DEBUG false;private final FragmentMana…...

70. Linux驱动开发与裸机开发区别,字符设备驱动开发

一、裸机驱动开发回顾 1、底层&#xff0c;跟寄存器打交道&#xff0c;有些MCU提供了库。 二、Linux驱动开发思维 1、Linux下驱动开发直接操作寄存器不现实。 2、根据Linux下的各种驱动框架进行开发。一定要满足框架&#xff0c;也就是Linux下各种驱动框架的掌握。 3、驱动最…...

【博客节选】再谈Unity 的 root motion

节选自 【Unity实战笔记】第二十三 root motion变更方向攻击 &#xff08;OnStateMove rootmotion rigidbody 使用的一些问题&#xff09; 小伙伴们应该对root motion非常困惑&#xff0c;包括那个bake into pose。 当xz bake into pose后&#xff0c;角色攻击动画与父节点产…...

26考研——栈、队列和数组_栈(3)

408答疑 文章目录 一、栈1、栈&#xff08;Stack&#xff09;的概念和特点定义术语操作特性示例直观理解栈的基本操作初始化栈判断栈是否为空入栈操作出栈操作读取栈顶元素销毁栈 栈的数学性质 2、栈的顺序存储结构顺序栈的定义栈顶指针初始化注意事项 共享栈共享栈的操作共享栈…...

“十五五”时期航空弹药发展环境分析

1&#xff0e;“十五五”时期航空弹药发展环境分析 &#xff08;标题&#xff1a;小二号宋体居中&#xff09; 一、建言背景介绍 &#xff08;一级标题&#xff1a;黑体三号&#xff0c;首行空两格&#xff09; 航空弹药作为现代战争的核心装备&#xff0c;其发展水平直接关乎…...

桥接模式的优点和典型实现

桥接模式的优点 桥接模式通过将抽象部分与实现部分分离&#xff0c;使得它们可以独立变化&#xff0c;从而提高系统的灵活性和可扩展性。以下是桥接模式的主要优点&#xff1a; 分离抽象和实现&#xff1a; 桥接模式将抽象部分和实现部分分离&#xff0c;使得两者可以独立变化…...

Kotlin 协程官方文档知识汇总(一)

1、协程基础 Kotlin 是一门仅在标准库中提供最基本底层 API 以便其他库能够利用协程的语言。与许多其他具有类似功能的语言不同&#xff0c;async 与 await 在 Kotlin 中并不是关键字&#xff0c;甚至都不是标准库的一部分。此外&#xff0c;Kotlin 的挂起函数概念为异步操作提…...

删除字符串邻近的重复项

1047. 删除字符串中的所有相邻重复项 - 力扣&#xff08;LeetCode&#xff09; 对于字符串中字符的匹配或者删除等问题&#xff0c;通常会用到栈这个数据结构&#xff0c;要保持这样一个思路。 对于这道题&#xff0c;可以遍历字符串&#xff0c;用栈存储&#xff0c;一旦遇到…...

基于 mxgraph 实现流程图

mxgraph 可以实现复杂的流程图绘制。mxGraph里的Graph指的是图论(Graph Theory)里的图而不是柱状图、饼图和甘特图等图(chart)&#xff0c;因此想找这些图的读者可以结束阅读了。 作为图论的图&#xff0c;它包含点和边&#xff0c;如下图所示。 交通图 横道图 架构图 mxGrap…...

动态路由机制MoE专家库架构在多医疗AI专家协同会诊中的应用探析

随着医疗人工智能技术的飞速进步,AI在医学领域的应用日益增多,尤其是在复杂疾病的诊断和治疗中,AI技术的应用带来了巨大的潜力。特别是动态路由机制混合专家(Mixture of Experts,MoE)架构,因其灵活、高效的特点,正逐渐成为实现多AI专家协同会诊的关键技术。通过将多个不…...

双工通信:WebSocket服务

&#xff08;一&#xff09;WebSocket概述 WebSocket 是基于 TCP 的一种新的网络协议。它实现了浏览器与服务器全双工通信——浏览器和服务器只需要完成一次握手&#xff0c;两者之间就可以创建持久性的连接&#xff0c; 并进行双向数据传输 注意;Websocket也只能由客户端先握…...

洪水灌溉算法 + 总结

文章目录 floodfill算法图像渲染题解代码 岛屿数量题解代码 岛屿的最大面积题解代码 被围绕的区域题解代码 太平洋大西洋水流问题题解代码 扫雷游戏题解代码 衣橱整理题解代码 总结 floodfill算法 1. 寻找相同性质的联通块&#xff0c;可以使用dfs或者bfs解决&#xff0c;比如…...

docker中间件部署

1.docker安装 # 1.卸载旧版本 yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine# 2.需要的安装包 yum install -y yum-utils# 3.设置镜像的仓库 # 3.1.默认是国外的&#x…...

LangChain4j(1):初识LangChain4j

1 什么是LangChain和LangChain4j LangChain是一个大模型的开发框架&#xff0c;使用LangChain框架&#xff0c;程序员可以更好的利用大模型的能力&#xff0c;大大提高编程效率。如果你是一个lava程序员&#xff0c;那么对LangChain最简单直观的理解就是&#xff0c;LangChain…...

基于 Swoole 的高性能 RPC 解决方案

文章精选推荐 1 JetBrains Ai assistant 编程工具让你的工作效率翻倍 2 Extra Icons&#xff1a;JetBrains IDE的图标增强神器 3 IDEA插件推荐-SequenceDiagram&#xff0c;自动生成时序图 4 BashSupport Pro 这个ides插件主要是用来干嘛的 &#xff1f; 5 IDEA必装的插件&…...