Linux网络编程实战:从字节序到UDP协议栈的深度解析与开发指南

news2025/4/19 15:08:06

网路通信的三大要素:协议,端口和IP

知识点1【字节序】

多字节在主机中的存放数据

多字节看成一个整体存储的顺序

为什么我们在文件中没有这个概念呢?

因为文件是字节流(流指针),流是以一个字节为操作单位,并不是多字节

字节序分为两种:大端和小端

大端格式:高字节数据存放在低地址

小端格式:低字节数据存放在低地址

记忆方式:只看低地址,看是存储的高字节数据还是低字节数据

小()对小 大上

大小端是系统决定的,我们不能更改。

Linux 都是小端的。

案例1:判断当前系统是大端还是小端

判断思路:判断低地址存放的是 低字节数据还是高字节数据

代码演示

代码运行结果:

数组是 不管是什么系统,第0个元素是低地址

知识点2【网络字节序和主机字节序】

1、如果计算机没有考虑字节序的问题,容易导致传输的数据错误

这种错误会现在异构计算机上:计算机的架构不同。小端架构和大端架构

小端主机和大端数据通信时,又有字节序的不同,导致数据错误,如下图

2、解决上述问题的方法

方法引入

我们各地都有各自的方言,为了让全国都能正常沟通,国家为此规定了普通话,将方言转换为普通话,就都能正常沟通了,普通话就是一个标准。

下图只是说明问题,并非实际过程

方法

网络 里的 数据必须是大端

因此上述的实际过程。

主机A(大端格式)传输数据,传到网络,发现是大端字节序,无需数据格式转换

主机B(小端格式)接受数据,知道网络传输的数据格式是大端格式,会进行类型格式的转换,转换为小端字节序

3、主机字节序和网络字节序

引入

那么问题又来了,主机不知道自己是什么字节序,那该如何判读是否需要数据转换呢?

因此 这里 引入和 网络字节序(net) 和主机字节序(host)

转换的过程,有需要引入两个函数

hton,ntoh:这两个函数都会进行 主机字节序 的 判断,根据判断结果决定需不需要转换。

总结

发送数据:需要将 主机字节序 转换为 网络字节序 hton

接收数据:需要将 网络字节序 转换为 主机字节序 ntoh

知识点2【字节序的转换函数】

1、主机字节序 转 网络字节序(发送)

#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);//转IP
uint16_t htons(uint16_t hostshort);//转端口号

函数介绍 只介绍htonl htons类似

  • 函数介绍

    功能:

    将 32 位主机字节序数据转换成网络字节序数据

    参数:

    hostint32:待转换的 32 位主机字节序数据

    返回值:

    成功:返回网络字节序的值

重复

端口号无符号短整型

IP地址 32位

mac地址 48位

2、网络字节序 转 主机字节序(接收)

#include <arpa/inet.h>
uint32_t ntohl(uint32_t netlong);//转ip
uint16_t ntohs(uint16_t netshort);//转端口号
  • 函数介绍

    功能:

    将 32 位网络字节序数据转换成主机字节序数据

    参数:

    uint32_t: unsigned int

    netint32:待转换的 32 位网络字节序数据

    返回值:

    成功:返回主机字节序的值

案例 htonl

代码演示

#include <stdio.h>
#include <arpa/inet.h> 

int main(int argc, char const *argv[])
{
    uint32_t num = 0x04030201;
    printf("num = %d\\n",num);
    printf("htonl(num) = %#x\\n",htonl(num));
    printf("htonl(num) = %d\\n",htonl(num));
    return 0;
}

代码运行结果

知识点3【地址转换函数】

这里的地址指的是IP地址

“10.9.11.5” 这种IP是 点分十进制串 (用户识别的IP地址)IPv4

“fe80::578a:738a:f506:f37a”这种IP是 冒分十六进制串 IPv6

但是:计算机 是用 32位无符号数据 存储的IP地址

大家判断一下 上面我写的这个字符串多少个字节

10个字节

那么 点分十进制串 最大的字节数是多少呢?

“192.168.100.101”

是16个字节(算’\0’)

因此我们以后 存储 点分十进制串 要用16个字节来存储

1、发送数据

需要将 点分十进制数串 转换为 32位无符号数

#include <arpa/inet.h>
int inet_pton(int af, const char *src, void *dst);
  • 函数介绍

    功能:

    分十进制串 转换为 无符号数网络IP

    参数:

    af: (address family)

    IPv4的点分十进制串→AF_INET

    IPv6的冒分十六进制串→AF_INET6

    src:输入参数,指向以空字符结尾的字符串,表示 IPv4 或 IPv6 地址。

    点分十进制串 和 冒分十六进制串

    dst: 输出参数,指向一个缓冲区,用于存储转换后的二进制数据

    返回值:

    • 1:成功转换。
    • 0:输入地址无效(例如,IPv4 字符串包含字母)。
    • -1:发生错误(如 af 参数不合法),可通过 errno 获取具体错误

代码演示

#include <stdio.h>
#include <arpa/inet.h>

int main(int argc, char const *argv[])
{
    //实现IP 点分十进制串 向 32位IP地址(IPv4)的转换
    //我们假设IP地址为:10.11.1.5
    char *str_ip = "10.11.1.5";
    u_int32_t addr = 0;
    inet_pton(AF_INET,str_ip,&addr);
    printf("addr = %u\\n",addr);

    //现在我们按照字符遍历一下
    unsigned char *p = (unsigned char *)&addr;
    printf("%d.%d.%d.%d\\n",*p,*(p + 1),*(p + 2),*(p + 3));

    
    return 0;
}

代码运行结果

这里我自己实现了一个 pton的函数,大家看一下,有助于大家更好地理解pton

自己实现的pton

int my_pton(char *str_ip,int *addr)
{
    //先进性数据提取
    char ch_p[4];
    int int_p[4];
    sscanf(str_ip,"%d.%d.%d.%d",&int_p[0],&int_p[1],&int_p[2],&int_p[3]);
    //这里的数据高位(第一个%d) 存储到了&int_p[0]中,而数组下标小的在低地址,与我们想要的相反,因此我们下面要转换过来

    //将数据提取到字符数组当中
    for (size_t i = 0; i < 4; i++)
    {
        if(int_p[i] > 255 || int_p[i] < 0)
        {
            return 0;
        }
        ch_p[i] = (unsigned char)int_p[i];
    }
    
    *addr = ch_p[0] << 24 | ch_p[1] << 16 | ch_p[2] << 8 | ch_p[3];//这里不需要强转,因为会自动类型转换
    //现在的顺序对了,但是此时是小端存储,但是pton的结果 我们分析出 是大端存储,因此我们需要 转换为大端存储
    *addr = htonl(*addr);

    return 1;
}

代码运行结果

2、接收数据

将32为无符号数据 转换成 点分十进制数串

  • 函数介绍

    #include <arpa/inet.h>
    const char *inet_ntop(int af, const void *src,char *dst, socklen_t size);
    

    功能:

    二进制格式的 IP 地址 转换为 可读字符串

    参数:

    af:Address Family

    src:输入参数,指向二进制格式的 IP 地址。

    dst:输出参数,指向用于存储结果字符串的缓冲区。

    size:缓冲区 dst 的字节长度。需足够大以防止溢出。

    返回值:

    • 成功:返回指向 dst 的指针(即转换后的字符串地址)。
    • 失败:返回 NULL,并设置 errno 表示具体错误。

知识点4【UDP编程概述】

1、socket

网络通信要解决的问题 是不同主机进程间的通信

三要素

1、IP地址

2、PORT

3、协议

socket:网络程序编程开发接口的统称

socket作用

提供不同主机上的进程之间的通信

socket特点

1、socket也称”套接字

2、是一个特殊的文件描述符(套接字),代表一个通信管道的一个端点

3、类似对文件的操作一样,可以使用read,write,close等函数对socket套接字进行网络数据的读取和发送等操作

4、得到套接字(描述符)的方法调用socket()

5、socket可读可写,且有端口和IP

注意

不要直接成socket是文件描述符,它是一种特殊的文件描述符,它有专属名称是套接字

2、UDP的编程流

bind 绑定函数,服务器是被动的,服务器给用户一个固定的端口,而这个固定的端口的提供 需要bind绑定函数来实现,可以通过端口找到该服务器。一旦绑定了这个端口,这个端口号其他进程就不可以再使用。

绑定 客户端也是可以有的,一旦绑定,发送消息,其他客户端就知道 是本端口发送的,其他客户端也可以通过这个端口找到该客户端

客户端:创建套接字,收,发,关闭套接字

服务器:创建,绑定,收,发,关闭(图中没有,记得加上)

关闭防火墙交流

背一下:

hton:将 主机字节序 转换为 网络字节序

ntoh:将 网络字节序 转换为 主机字节序

pton:字符串转换 为 大端的二进制数据

ntop:大端二进制数据 转换为 字符串

3、socket函数创建一个套接字(通信的端点)

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int socket(int family,int type,int protocol);

功能:

创建一个用于网络通信的 socket 套接字(描述符)

参数:

family:协议族(AF_INET、AF_INET6、PF_PACKET 等)

type:套接字类(SOCK_STREAM、SOCK_DGRAM、SOCK_RAW 等)

protocol:协议类别(0、IPPROTO_TCP、IPPROTO_UDP 等

返回值:

套接字

特点:

创建套接字时,系统不会分配端口

代码演示

代码运行结果

4、IPv4地址结构体

**作用:**定义 地址结构体变量

#include <netinet/in.h>
struct in_addr
{
	in_addr_t s_addr;//4 字节
};

struct sockaddr_in//IPv4地址 结构体
{
	sa_family_t sin_family;//2 字节
	in_port_t sin_port;//2 字节
	struct in_addr sin_addr;//4 字节
	char sin_zero[8]//8 字节
};

//IPv6地址结构体 :sockaddr_in6

sin_zero 全部需要补零。作用是将结构体补充成16个字节

我们定义结构体后,建议先把结构体清零

5、通用地址结构体

对传递给函数的参数进行类型转换 不做赋值操作

struct sockaddr
{
	sa_family_t sa_family; // 2 字节
	char sa_data[14] //14 字节
};

这里解释一下,为什么要这个结构体,由family可以看出,我们可以选择IPv4 也可以选择IPv6,IPv4和IPv6是两种协议,我们在设计sendto函数的时候,由于它们所需的地址结构体是不同的,但是我们又想用同一个sendto函数。

我们就定义了一个通用地址结构体,通用结构体是16个字节,它只有前两个字节有效也就是family成员,代码中会对family就行判断确定是IPv4 还是IPv6,然后函数内部进行结构体类型强转。就可以实现一个sendto函数完成IPv4和IPv6的通用。

综上在这里 通用地址结构体的作用类似于:**void ***

大家可以在下面sendto介绍中看一下,to 的类型是什么,还有recvform中from的的类型是什么。

6、sendto发送UDP消息

TCP消息是用send发送的。

套接字,内容,大小,0,目标,大小

#include <sys/types.h>
#include <sys/socket.h>
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
                const struct sockaddr *dest_addr, socklen_t addrlen);

功能:

向 to 结构体指针中指定的 ip,发送 UDP 数据

参数:

sockfd:套接字

buf:发送数据缓冲区

nbytes: 发送数据缓冲区的大小

flags:一般为 0

行为标志,网络数据比较复杂,紧急指针等需要特殊处理,这里我们写0就行

to:指向目的主机地址结构体的指针

addrlen:to 所指向内容的长度

返回值:

成功:发送数据的字符数

失败: -1

注意:

通过 to 和 addrlen 确定目的地址

可以发送 0 长度的 UDP 数据包

代码演示

#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
int main(int argc, char const *argv[])
{
    //创建一个 套接字
    int sockfd = 0;
    sockfd = socket(AF_INET,SOCK_DGRAM,0);
    if(sockfd < 0)
    {
        perror("socket");
        return 0;
    }
    printf("sockfd = %d\\n",sockfd);//遍历一下sockfd

    //sendto 
    //输入数据
    printf("请输入数据:\\n");
    char  buf[64] = "";
    fgets(buf,sizeof(buf),stdin);
    buf[strlen(buf) - 1] = 0;
    //地址结构体创建
    struct sockaddr_in addr;
    memset(&addr,0,sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(8080);
    inet_pton(AF_INET,"192.168.136.1",&addr.sin_addr.s_addr);
    //sendto 发送数据
    int ret = sendto(sockfd,buf,strlen(buf),0,(struct sockaddr *)(&addr),sizeof(addr));
    if(ret < 0)
    {
        perror("sendto");
        return 0;
    }
    return 0;
}

代码运行结果

在上面运行结果我们看到,发送端口的端口号是随机的

这个端口是如何来的呢?

是又第一次sendto随机分配的,记住只有第一次send 才会分配,比如我们在程序中多次发送数据,在第一次sendto之后,端口号将不改变,我们将上面的代码加上循环

可以看到端口号没有改变。但是 结束该进程,开启一个新进程后,端口号会改变

但实际使用过程中,总不能端口号一直在改变,因此我们下面需要学习一下bind()函数设置固定的端口

7、bind给套接字绑定固定的 IP和端口

绑定的位置应在 socket()之后,在sendto()/recvfrom()之前

绑定函数只能绑定 本地机的IP和端口

int bind(int sockfd, const struct sockaddr *myaddr,socklen_t addrlen);

功能:

将本地协议地址 与 sockfd 绑定

参数:

sockfd: socket 套接字

myaddr: 指向特定协议的地址结构指针

addrlen:该地址结构的长度

返回值:

成功:返回 0

失败:其他

代码演示

#include <stdio.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
    //创建socket
    int sockfd = 0;
    sockfd = socket(AF_INET,SOCK_DGRAM,0);
    if(sockfd < 0)
    {
        perror("socket");
        return 0;
    }
    printf("sockfd = %d\\n",sockfd);

    //固定端口 bind 套接字 地址结构体 大小
    struct sockaddr_in my_addr;
    memset(&my_addr,0,sizeof(my_addr));
    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(8000);
    my_addr.sin_addr.s_addr = htonl(INADDR_ANY);//INADDR_ANY==0,通配地址,让协议栈取本地机去找IP
    int ret = bind(sockfd,(struct sockaddr *)&my_addr,sizeof(my_addr));
    if(ret != 0)
    {
        perror("bind");
        return 0;
    }

    //发送消息 套接字 大小 flags 地址结构体 大小
    //键盘获取输入
    char buf[64] = "";
    fgets(buf,sizeof(buf),stdin);
    buf[strlen(buf)-1] = 0;

    //地址结构体的配置
    struct sockaddr_in addr;
    memset(&addr,0,sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(7000);
    inet_pton(AF_INET,"192.168.136.1",&addr.sin_addr.s_addr);
    sendto(sockfd,buf,sizeof(buf),0,(struct sockaddr *)&addr,sizeof(addr));
    
    
    //关闭套接字描述符
    close(sockfd);
    return 0;
}

代码运行结果

可以看到即使是两个进程,端口号也是不变的

8、recvfrom 接收数据(带阻塞)

如果负责收数据,记得绑定固定的端口及IP

ssize_t recvfrom(int sockfd, void *buf,size_t nbytes,int flags,
											struct sockaddr *from,socklen_t *addrlen);

功能:

接收 UDP 数据,并将源地址信息保存在 from 指向的结构中

参数:

sockfd:套接字

buf:接收数据缓冲区

nbytes:接收数据缓冲区的大小

flags:套接字标志(常为 0)

from:源地址结构体指针,用来保存数据的来源**(可以为NULL)**

addrlen: from 的长度**(可以是NULL)**

和送礼一样,谁送的不重要,重要的是礼物

注意:

通过 from 和 addrlen 参数存放数据来源信息

from 和 addrlen 可以为 NULL, 表示不保存数据来源

返回值:

成功:接收到的字符数

失败: -1

注意:

这个返回值 我们可以利用返回值 判断数据是否收完。

接收到的数据如果小于收到的内容nybte,则表示收完了,停止接收数据。

有可能接收图片(RGB),因此我们存的话需要用unsigned char接收。

又由于以太网最大传输单元(MTU)是1500个,因此接受数组的个数1500即可

代码演示

#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <string.h>

int main(int argc, char const *argv[])
{
    //创建一个 socket
    int sockfd = socket(AF_INET,SOCK_DGRAM,0);
    if(sockfd < 0)
    {
        perror("socket");
        return 0;
    }
    printf("sockfd = %d\n",sockfd);

    //bind 固定端口于IP 必须要进行的操作 fd,地址结构体,大小
    struct sockaddr_in my_addr;
    memset(&my_addr,0,sizeof(my_addr));
    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(6000);
    my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    int ret = bind(sockfd,(struct sockaddr *)&my_addr,sizeof(my_addr));
    if(ret != 0)
    {
        perror("bind");
        return 0;
    } 

    //接收数据
    while(1)
    {
        unsigned char buf[1500] = "";
        struct sockaddr_in addr;
        memset(&addr,0,sizeof(addr));
        int addr_len = sizeof(addr);

        int ret = recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr *)&addr,&addr_len);
        if(ret < 0)
        {
            perror("recvfrom");
            return 0;
        }
        //数据存储在buf中,数据的长度为ret
        //IP来源于addr.sin_addr.s_addr,需要处理
        //端口号为addr.sin_port,需要进行字节序转换
        //IP处理
        char str_add[16] = "";
        inet_ntop(AF_INET,&addr.sin_addr.s_addr,str_add,sizeof(str_add));
        //端口字节序转换
        int port = ntohs(addr.sin_port);

        //遍历一下
        printf("从IP:%s 端口号:%hu 接收到的数据为:%s,数据长度为%d",str_add,port,buf,ret);
    }

    //关闭 套接字描述符
    close(sockfd);

    return 0;
}

结束

代码重在练习!

代码重在练习!

代码重在练习!

今天的分享就到此结束了,希望对你有所帮助,如果你喜欢我的分享,请点赞收藏夹关注,谢谢大家!!!

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

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

相关文章

赋能能源 | 智慧数据,构建更高效智能的储能管理系统

行业背景 随着新能源产业的快速发展&#xff0c;大规模储能系统在电力调峰、调频及可再生能源消纳等领域的重要性日益凸显。 储能电站作为核心基础设施&#xff0c;其能量管理系统&#xff08;EMS&#xff09;需要处理海量实时数据&#xff0c;包括电池状态、功率变化、环境监…

【音视频】音视频FLV合成实战

FFmpeg合成流程 示例本程序会⽣成⼀个合成的⾳频和视频流&#xff0c;并将它们编码和封装输出到输出⽂件&#xff0c;输出格式是根据⽂件扩展名⾃动猜测的。 示例的流程图如下所示。 ffmpeg 的 Mux 主要分为 三步操作&#xff1a; avformat_write_header &#xff1a; 写⽂件…

猪行为视频数据集

猪行为数据集包含 23 天(超过 6 周)的日间猪行为视频,这些视频由近乎架空的摄像机拍摄。视频已配准颜色和深度信息。数据以每秒 6 帧的速度捕获,并以 1800 帧(5 分钟)为一批次进行存储。大多数帧显示 8 头猪。 这里可以看到颜色和深度图像的示例: 喂食器位于图片底部中…

【网络技术_域名解析DNS】一、DNS 基础剖析及其原理

一、DNS 在互联网架构中的基石地位​ 当我们在浏览器地址栏输入www.baidu.com按下回车键的瞬间&#xff0c;一场跨越全球的 “数字寻址游戏” 便悄然启动。DNS&#xff08;Domain Name System&#xff09;作为互联网的核心基础设施&#xff0c;承担着将人类易读的域名转换为机…

Java学习小册:Java并发容器与原子类

在Java并发编程中&#xff0c;并发容器和原子类是管理共享数据的重要工具。它们提供了线程安全的数据结构和原子操作&#xff0c;确保在多线程环境下数据的一致性和操作的正确性。本文将深入探讨Java中的并发容器和原子类&#xff0c;包括它们的基本概念、使用方法、关键类及其…

摄影跟拍预定|基于java+vue的摄影跟拍预定管理系统(源码+数据库+文档)

摄影跟拍预定管理系统 目录 基于SprinBootvue的摄影跟拍预定管理系统 一、前言 二、系统设计 三、系统功能设计 1系统功能模块 2管理员功能模块 3摄影师功能模块 4用户功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获…

【HFP】深入解析蓝牙 HFP 协议中呼叫转移、呼叫建立及保持呼叫状态的机制

目录 一、核心指令概述 1.1 ATCMER&#xff1a;呼叫状态更新的 “总开关” 1.2 ATBIA&#xff1a;指示器的 “精准控制器” 1.3 指令对比 1.4 指令关系图示 二、CIEV 结果码&#xff1a;状态传递的 “信使” 2.1 工作机制 2.2 三类核心指示器 三、状态转移流程详解 3…

Linux:显示 -bash-4.2$ 问题(CentOS 7)

文章目录 一、原因二、错误示例三、解决办法 一、原因 在 CentOS 7 系统中&#xff0c;如果你看到命令行提示符显示为 -bash-4.2$&#xff0c;一般是 Bash shell 正在运行&#xff0c;并且它没有找到用户的个人配置文件&#xff0c;或者这些文件有问题而未能成功加载。这个提示…

视频监控EasyCVR视频汇聚平台接入海康监控摄像头如何配置http监听功能?

一、方案概述 本方案主要通过EasyCVR视频管理平台&#xff0c;实现报警信息的高效传输与实时监控。海康监控设备能通过HTTP协议将报警信息发送至指定的目的IP或域名&#xff0c;而EasyCVR平台则可以接收并处理这些报警信息&#xff0c;同时提供丰富的监控与管理功能&#xff0…

DAY09:【pytorch】nn网络层

1、卷积层 1.1 Convolution 1.1.1 卷积操作 卷积运算&#xff1a;卷积核在输入信号&#xff08;图像&#xff09;上滑动&#xff0c;相应位置上进行乘加卷积核&#xff1a;又称为滤波器、过滤器&#xff0c;可认为是某种模式、某种特征 1.1.2 卷积维度 一般情况下&#xf…

跟康师傅学Java-面向对象(基础)

跟康师傅学Java-面向对象(基础) 学习面向对象内容的三条主线(非官方) ①Java类及类的成员:(重点)属性、方法、构造器;(熟悉)代码块、内部类 ②面向对象的特征:封装、继承、多态、(抽象) ③其他关键字的使用:this、super、package、import、static、final、inte…

2000-2017年各省国有经济煤气生产和供应业固定资产投资数据

2000-2017年各省国有经济煤气生产和供应业固定资产投资数据 1、时间&#xff1a;2000-2017年 2、来源&#xff1a;国家统计局、能源年鉴 3、指标&#xff1a;行政区划代码、城市、年份、国有经济煤气生产和供应业固定资产投资 4、范围&#xff1a;31省 5、指标说明&#x…

线性代数 | 知识点整理 Ref 3

注&#xff1a;本文为 “线性代数 | 知识点整理” 相关文章合辑。 因 csdn 篇幅合并超限分篇连载&#xff0c;本篇为 Ref 3。 略作重排&#xff0c;未整理去重。 图片清晰度限于引文原状。 如有内容异常&#xff0c;请看原文。 《线性代数》总复习要点、公式、重要结论与重点释…

网络层IP协议知识大梳理

全是通俗易懂的讲解&#xff0c;如果你本节之前的知识都掌握清楚&#xff0c;那就速速来看我的IP协议笔记吧~ 自己写自己的八股&#xff01;让未来的自己看懂&#xff01; &#xff08;全文手敲&#xff0c;受益良多&#xff09; 网路基础3 网路层 TCP并没有把数据发到网路…

【Web前端技术】第二节—HTML标签(上)

hello&#xff01;好久不见—— 做出一个属于自己的网站&#xff01; 云边有个稻草人-个人主页 Web前端技术—本篇文章所属专栏 目录 一、HTML 语法规范 1.1 基本语法概述 1.2 标签关系 二、HTML 基本结构标签 2.1 第一个 HTML 网页 2.2 基本结构标签总结 三、网页开发…

08软件测试需求分析案例-删除用户

删除用户是后台管理菜单的一个功能模块&#xff0c;只有admin才有删除用户的权限。不可删除admin。 1.1 通读文档 通读需求规格说明书是提取信息&#xff0c;提出问题&#xff0c;输出具有逻辑、规则、流程的业务步骤。 信息&#xff1a;此功能应为用户提供确认删除的功能。…

十三种通信接口芯片——《器件手册--通信接口芯片》

目录 通信接口芯片 简述 基本功能 常见类型 应用场景 详尽阐述 1 RS485/RS422芯片 1. RS485和RS422标准 2. 芯片功能 3. 典型芯片及特点 4. 应用场景 5. 设计注意事项 6. 选型建议 2 RS232芯片 1. RS232标准 2. 芯片功能 3. 典型芯片及特点 4. 应用场景 5. 设计注意事项 6…

反转一个字符串

用数组栈实现 void Reverse(char *C, int len) {top -1;for(int i 0; i < len; i){push(C[i]);}for(int i 0; i < len; i){C[i] Top();pop();} } 全部函数 #include <stdio.h> #include <stdlib.h> #include <string.h>#define MAX_SIZE 101int …

【限流算法】计数器、漏桶、令牌桶算法

1 计数器 使用计数器实现限流&#xff0c;可限制在指定时间间隔内请求数小于阈值的情况&#xff0c;但存在临界问题。如图1-17所示&#xff0c;假设每分钟系统限流500个请求&#xff0c;在XX:00:59时刻系统接收到500个请求&#xff0c;在XX:01:00时刻系统又接收到500个请求&am…

秘密任务 2.0:如何利用 WebSockets + DTOs 设计实时操作

在之前的文章中&#xff0c;我们探讨了为什么 DTO 是提升 API 效率和安全性的秘密武器。现在&#xff0c;我们进入了一个全新的场景——我们将深入探讨如何通过 WebSockets DTOs 实现实时操作&#xff01; Agent X 正在进行一项高风险的卧底任务。突然&#xff0c;总部更新了…