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

网络基础(2)

目录

    • 1. 端口号
    • 2. 套接字socket
    • 3. 网络通信
      • 3.1 sockaddr与sockaddr_in
      • 3.2 接口
        • 服务端
        • 3.2.1 创建套接字,打开网络文件
        • 3.2.2 给该服务器绑定端口和ip(特殊处理)
        • 3.2.3 初始化相关服务器
        • 3.2.4 提供服务
        • 客户端
        • 3.2.5 绑定
        • 3.2.6 使用服务
    • 4. makefile实现:
    • 5. 整体代码

1. 端口号

IP能够唯一地标识互联网中的一台主机;而端口号能够唯一地标识一台机器上的唯一一个进程。

那么这两个因素加起来,就构成了能够标识互联网上的唯一一个进程。这就是端口号与IP的联系。

2. 套接字socket

整个网络看作是一个大的OS,所有网络上网行为,都是在这里面实现进程间通信的。

IP地址+port端口号 = socket

端口号之于进程PID,就相当于身份证号之于学生学号。

  • 为什么有了PID,在网络里还需要端口号来进行标识?

这就好比学校不用身份证来对学生信息进行管理、录入。因为学校内部会有更合适的管理系统,采用自己一套的管理方式能够使管理更加得心应手,也不惧怕外部环境的改变,实现与外部解耦。PID和端口号也是这个原理。

3. 网络通信

3.1 sockaddr与sockaddr_in

要实现网络通信,首先是要找到目标主机,其次是找到该主机上的目标进程。

而进程具有独立性,要实现网络通信需要让两个进程看到同一份资源,这份资源就是网络。

应用层的下一层就是传输层,传输层有TCP/UDP协议。

  • 统一接口

对于将要介绍的sock接口,要先说明一个概念,就是sockarr结构:由于各种网络协议的实现方式不同,导致接口需要对应设计,所以干脆就设计出来了一个通用的接口,该参数统一为sockaddr。

socket API是一层抽象的网络编程接口,适用于各种底层网络协议,如IPv4、IPv6,以及UNIX DomainSocket。 然而, 各种网络协议的地址格式并不相同。

目前我们采用的是struct sockaddr,这是一个通用接口,也即是说,可以兼容后两个接口类型的参数。

通用接口与其他两个不同协议的接口:

在这里插入图片描述

虽然socket api的接口是sockaddr, 但是我们真正在基于IPv4编程时, 使用的数据结构是sockaddr_in; 这个结构里主要有三部分信息: 地址类型, 端口号, IP地址。

sockaddr与sockaddr_in其实都是结构体类型:

  1. sockaddr

它把目标地址和端口信息实现在一起:

struct sockaddr{sa_family_t sin_family;//16位地址类型家族char sa_data[14];//14位长度地址数据,包含套接字中的目标地址和端口信息
}
  1. sockaddr_in

sockaddr_in的头文件包含在:

#include <netinet/in.h>
#include <arpa/inet.h>

该结构体解决了sockaddr的缺陷,把port和addr 分开储存在两个变量中,如下

typedef uint16_t in_port_t;//十六位数字struct sockaddr_in{sa_family_t   sin_family;//16位地址类型家族in_port_t sin_port;//16位端口号struct in_addr    sin_addr;//32位ip地址unsigned char sin_zero;//未使用
}

in_addr其实就是32位的IPv4地址:

typedef uint32_t in_addr_t;struct in_addr{In_addr_t  s_addr;    //32位IPv4地址
};
  1. sockaddr_un
struct sockaddr_un{//16位地址类型//108字节路径名
}

IPv4、IPv6地址类型分别定义为常数AF_INET、AF_INET6. 这样,只要取得某种sockaddr结构体的首地址,不需要知道具体是哪种类型的sockaddr结构体,就可以根据地址类型字段确定结构体中的内容。

socket API可以都用struct sockaddr * 类型表示, 在使用的时候需要强制转化成sockaddr_in; 这样的好处是程序的通用性, 可以接收IPv4, IPv6, 以及UNIX Domain Socket各种类型的sockaddr结构体指针做为参数。

3.2 接口

服务端

3.2.1 创建套接字,打开网络文件

// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)
int socket(int domain, int type, int protocol);
  1. 参数:

domain就是用来区分传入的是哪个协议种类。

type代表协议特性,是套接字类型。比如流式套结、原始套结等。

proyocol在tcp中只需要全部设置为0。

  1. 返回值:创建成功后,新的套接字会返回一个文件描述符。
#include <iostream>
#include <cerrno>
int main()
{int sock = socket(AF_INET,SOCK_DGRAM,0);if(sock < 0){std::cout<<"socket create error!"<<errno<<std::endl;return 1;}std::cout<<"sock:"<<sock<<std::endl;return 0;
}

运行结果:

在这里插入图片描述

3.2.2 给该服务器绑定端口和ip(特殊处理)

作为一个服务器,对应的服务器地址(IP+port)是必须要被客户(人、软件、浏览器)所知晓的,并且不能轻易地被改变。

  • 首先要绑定端口号
// 绑定端口号 (TCP/UDP, 服务器)
int bind(int sockfd, const struct sockaddr *addr,
socklen_t address_len);
  1. 参数

sockfd代表创建好的套接字的文件描述符;addr代表需要用户指定服务器的相关socket信息,address_len代表传入的结构体大小。

  1. 返回值

绑定成功返回0,失败返回-1,也可以是错误码。

3.2.3 初始化相关服务器

这里的参数addr是相关服务器的信息,所以要bind,就要先初始化好addr的信息:

首先定义一个sockaddr_in类型的结构体,因为我们平时传的addr其实是sockaddr_in类型的,只需要在绑定的时候做一下强转即可。

那么接下来就是将它里面的对应字段全部初始化:

const uint16_t port = 8080;
struct sockaddr_in local;
local.sin_family = AF_INET; //IPV4
local.sin_port = htons(port); //该端口号是主机序列,要改成网络序列
local.sin_addr.s_addr = INADDR_ANY;

其中port是主机序列,需要转为网络序列,使用的是htons函数:

h是host代表主机,n代表network网络:

在这里插入图片描述

剩下最后一个字段初始化为INADDR_ANY的意思是:由该服务器发送的,到任意主机(IP)上的数据都能被你的网络进程接收。

如果不这样初始化,而是绑定了确定的IP,例如:

//inet_addr函数将地址从数点法转化为整数IP
//网络需要的是整数表示IP而不是数点法表示的地址
local.sin_addr.s_addr = inet_addr("xx.xxx.xx.xxx");

这样的话,只有发送到该IP的数据才能被你进程接收,所以一般不这么写。

并且云服务器不直接绑定公网IP。

然后就可以进行绑定:

if(bind(sock,(struct sockaddr*)&lockal,sizeof(local)) < 0){std::cout << "bind error : " << errno << std::endl;return 2;
}

3.2.4 提供服务

绑定完成以后,等待他人给自己的服务器发送信息,是接收的过程。

  • recvfrom

udp的数据读取不是用文件的接口,而是有专门的接口recvfrom:

在这里插入图片描述

参数:分别是自身套接字fd、读完的数据放到buf、读len大小、读的方式flag(默认0),剩下最后两个代表的是和你的服务器通信的客户端的信息,是一个输出型参数,作用是如需要返回数据给它,就可以拿到其地址返回。

  • sendto

给对端发信息,用的是sendto

其他参数都一样,最后两个参数代表的是要给谁发:

在这里插入图片描述

由此可以提供服务:

// 3. 提供服务
#define NUM 1024
char buffer[NUM];
bool quit = false;
while(!quit){struct sockaddr_in send;socklen_t len = sizeof(send);//开始读recvfrom(sock,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&send,&len);std::cout << "client" << buffer << std::endl;//收到以后回复hellostd::string echo = "hello";sendto(sock,echo.c_str(),echo.size(),0,(struct sockaddr*)&send,len);}

客户端

3.2.5 绑定

客户端不需要显示绑定。

对于客户端来说,也必须要有套接字,但是它不需要显示绑定。因为一旦绑定了,它就要和某一个端口关联了,该端口不一定会存在,或者被占用,那么该客户端将无法使用。

对于服务端来说,端口必须要明确,并且不能变更;而对于客户端,只要有端口就行,因为是客户端访问他人。所以客户端一般都是由OS在发送数据的时候自动绑定,采用的是随机端口。

// 1. 创建
int sockfd = socket(AF_INET,SOCK_DGRAM,0);
if(sockfd < 0){std::cout<<"socket create error!"<<errno<<std::endl;return 1;
}
std::cout<<"sock:"<<sockfd<<std::endl;

3.2.6 使用服务

实现基本和服务端一样,但是由于自定义遵守./udp_client server_ip server_port的格式,所以要用到命令行参数来规范行为,不规范的话会打印使用手册。

void Usage(std::string proc)
{std::cout << "Usage: \n\t"<< proc << " server_ip server_port" << std::endl;
}
int main(int argc,char* argv[])
{if(argc != 3){Usage(argv[0]);return 0;}// 1. 创建int sockfd = socket(AF_INET,SOCK_DGRAM,0);if(sockfd < 0){std::cout<<"socket create error!"<<errno<<std::endl;return 1;}std::cout<<"client:sock:"<<sockfd<<std::endl;//客户端也必须要有套接字//不需要显示bind// 2. 使用服务// ./udp_client server_ip server_port的格式struct sockaddr_in server;server.sin_family = AF_INET;server.sin_port = htons(atoi(argv[2]));server.sin_addr.s_addr = inet_addr(argv[1]);while(1){// 1. 数据来源 std::string s;std::cout<<"输入# ";std::cin>>s;// 2. 发给谁sendto(sockfd,s.c_str(),s.size(),0,(struct sockaddr*)&server,sizeof(server));//此处tmp就是一个”占位符“struct sockaddr_in tmp;socklen_t len = sizeof(tmp);char buffer[1024];recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&tmp, &len);std::cout << "server echo# " << buffer << std::endl;}return 0; 
}

由于云服务器需要手动在后台开通窗口才可通信,所以IP使用127.0.0.1来测试

下列运行结果:

客户端:
在这里插入图片描述

服务端:

在这里插入图片描述

4. makefile实现:

.PHONY:all
all:udp_server udp_clientudp_server:udp_server.ccg++ -o $@ $^ -std=c++11udp_client:udp_client.ccg++ -o $@ $^ -std=c++11.PHONY:clean
clean:rm -f udp_server udp_client

5. 整体代码

服务端:

#include <netinet/in.h>
#include <arpa/inet.h>
#include <iostream>
#include <cerrno>const uint16_t port = 8080;
int main()
{// 1. 创建套接字,打开网络文件int sock = socket(AF_INET,SOCK_DGRAM,0);if(sock < 0){std::cout<<"socket create error!"<<errno<<std::endl;return 1;}std::cout<<"server:sock:"<<sock<<std::endl;// 2. 给该服务器绑定端口和ipstruct sockaddr_in local;local.sin_family = AF_INET; //IPV4local.sin_port = htons(port); //该端口号是主机序列,要改成网络序列local.sin_addr.s_addr = INADDR_ANY;if(bind(sock,(struct sockaddr*)&local,sizeof(local)) < 0){std::cout << "bind error : " << errno << std::endl;return 2;}// 3. 提供服务#define NUM 1024char buffer[NUM];bool quit = false;while(!quit){struct sockaddr_in send;socklen_t len = sizeof(send);recvfrom(sock,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&send,&len);std::cout << "client say# " << buffer << std::endl;//收到以后回复hellostd::string echo = "hello";sendto(sock,echo.c_str(),echo.size(),0,(struct sockaddr*)&send,len);}return 0;
}

客户端:

#include <iostream>
#include <string>
#include <cerrno>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>//正确用法
// ./udp_client server_ip server_port的格式
void Usage(std::string proc)
{std::cout << "Usage: \n\t"<< proc << " server_ip server_port" << std::endl;
}
int main(int argc,char* argv[])
{if(argc != 3){Usage(argv[0]);return 0;}// 1. 创建int sockfd = socket(AF_INET,SOCK_DGRAM,0);if(sockfd < 0){std::cout<<"socket create error!"<<errno<<std::endl;return 1;}std::cout<<"client:sock:"<<sockfd<<std::endl;//客户端也必须要有套接字//不需要显示bind// 2. 使用服务// ./udp_client server_ip server_port的格式struct sockaddr_in server;server.sin_family = AF_INET;server.sin_port = htons(atoi(argv[2]));server.sin_addr.s_addr = inet_addr(argv[1]);while(1){// 1. 数据来源 std::string s;std::cout<<"输入# ";std::cin>>s;// 2. 发给谁sendto(sockfd,s.c_str(),s.size(),0,(struct sockaddr*)&server,sizeof(server));//此处tmp就是一个”占位符“struct sockaddr_in tmp;socklen_t len = sizeof(tmp);char buffer[1024];recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&tmp, &len);std::cout << "server echo# " << buffer << std::endl;}return 0; 
}

相关文章:

网络基础(2)

目录1. 端口号2. 套接字socket3. 网络通信3.1 sockaddr与sockaddr_in3.2 接口服务端3.2.1 创建套接字&#xff0c;打开网络文件3.2.2 给该服务器绑定端口和ip&#xff08;特殊处理&#xff09;3.2.3 初始化相关服务器3.2.4 提供服务客户端3.2.5 绑定3.2.6 使用服务4. makefile实…...

掌握Spring Cloud Gateway:构建高性能API网关的原理和实践

Spring Cloud Gateway 是一个基于 Spring Boot 的 API 网关&#xff0c;用于构建微服务架构中的网关服务。它提供了统一的路由、请求转发、过滤器、负载均衡、熔断等功能&#xff0c;帮助开发者更好地管理和控制微服务系统的请求流量。 本文将介绍 Spring Cloud Gateway 的原理…...

NAST概述

一、NATS介绍 NATS是由CloudFoundry的架构师Derek开发的一个开源的、轻量级、高性能的&#xff0c;支持发布、订阅机制的分布式消息队列系统。它的核心基于EventMachine开发&#xff0c;代码量不多&#xff0c;可以下载下来慢慢研究。 不同于Java社区的kafka&#xff0c;nats…...

【JS知识点】——原型和原型链

文章目录原型和原型链构造函数原型显式原型&#xff08;prototype&#xff09;隐式原型&#xff08;\_\_proto\_\_&#xff09;原型链总结原型和原型链 在js中&#xff0c;原型和原型链是一个非常重要的知识点&#xff0c;只有理解原型和原型链&#xff0c;才能深刻理解JS。在…...

c盘怎么清理到最干净?有什么好的清理方法

c盘怎么清理到最干净?有什么好的清理方法&#xff1f;清理C盘空间是电脑维护的重要步骤之一。C盘是Windows操作系统的核心部分&#xff0c;保存了许多重要的系统文件&#xff0c;因此空间不足会影响计算机的性能和稳定性。下面是一些清理C盘空间的方法 一.清理临时文件 在使用…...

day26_HTML

今日内容 上课同步视频:CuteN饕餮的个人空间_哔哩哔哩_bilibili 同步笔记沐沐霸的博客_CSDN博客-Java2301 零、 复习昨日 一、二阶段介绍 二、HTML 零、 复习昨日 见代码 一、二阶段介绍 第一阶段: 基础入门 java基本语法编程基础(方法,数组)面向对象编程常用类高级(IO,线程,新…...

深度剖析C语言预处理

致前行的人&#xff1a; 人生像攀登一座山&#xff0c;而找寻出路&#xff0c;却是一种学习的过程&#xff0c;我们应当在这过程中&#xff0c;学习稳定冷静&#xff0c;学习如何从慌乱中找到生机。 目录 1.程序翻译过程&#xff1a; 2.字符串宏常量 3.用宏定义充当注释符号 4…...

【WPF 值转换器】ValueConverter 进阶用法

【WPF 值转换器】ValueConverter 进阶用法介绍基类实现子类实现效果介绍 值转换器在WPF开发中是非常常见的&#xff0c;当然不仅仅是在WPF开发中。值转换器可以帮助我们很轻松地实现&#xff0c;界面数据展示的问题&#xff0c;如&#xff1a;模块隐藏显示、编码数据展示为可读…...

Vue2的基本使用

一、vue的基本使用 第一步 引入vue.js文件 <script src"https://cdn.staticfile.org/vue/2.7.0/vue.min.js"></script> 或者<script src"./js/vue.js"></script> 第二步 在body中设置一个挂载点 {{msg}} <div id"app…...

【云原生kubernetes】k8s数据存储之Volume使用详解

目录 一、什么是Volume 二、k8s中的Volume 三、k8s中常见的Volume类型 四、Volume 之 EmptyDir 4.1 EmptyDir 特点 4.2 EmptyDir 实现文件共享 4.2.1 关于busybox 4.3 操作步骤 4.3.1 创建配置模板文件yaml 4.3.2 创建Pod 4.3.3 访问nginx使其产生访问日志 4.3.4 …...

SerDes---CDR技术

1、为什么需要CDR 时钟数据恢复主要完成两个工作&#xff0c;一个是时钟恢复&#xff0c;一个是数据重定时&#xff0c;也就是数据的恢复。时钟恢复主要是从接收到的 NRZ&#xff08;非归零码&#xff09;码中将嵌入在数据中的时钟信息提取出来。 2、CDR种类 PLL-Based CDROve…...

如何实现在on ethernetPacket中自动回复NDP response消息

对于IPv4协议来说,如果主机想通过目标ipv4地址发送以太网数据帧给目的主机,需要在数据链路层填充目的mac地址。根据目标ipv4地址查找目标mac地址,这是ARP协议的工作原理 对于IPv6协议来说,根据目标ipv6地址查找目标mac地址,它使用的不是ARP协议,而是邻居发现NDP(Neighb…...

CSS清楚浮动

先看看关于浮动的一些性质 浮动使元素脱离文档流 浮动元素可以设置宽高&#xff0c;在CSS中&#xff0c;任何元素都可以浮动&#xff0c;浮动元素会生成一个块级框&#xff0c;而不论其本身是何种元素。 如果没有给浮动元素指定高度&#xff0c;&#xff0c;那么它会以内容的…...

HTTPS详解(原理、中间人攻击、CA流程)

摘要我们访问浏览器也经常可以看到https开头的网址&#xff0c;那么什么是https&#xff0c;什么是ca证书&#xff0c;认证流程怎样&#xff1f;这里一一介绍。原理https就是httpssl&#xff0c;即用http协议传输数据&#xff0c;数据用ssl/tls协议加密解密。具体流程如下图&am…...

EventLoop机制

JavaScript 是单线程的语言 JavaScript 是一门单线程执行的编程语言。也就是说&#xff0c;同一时间只能做一件事情。 单线程执行任务队列的问题&#xff1a; 如果前一个任务非常耗时&#xff0c;则后续的任务就不得不一直等待&#xff0c;从而导致程序假死的问题。 同步任…...

倒立摆建模

前言 系统由一辆具有动力的小车和安装在小车上的倒立摆组成&#xff0c;系统是不稳定&#xff0c;我们需要通过控制移动小车使得倒立摆保持平衡。 具体地&#xff0c;考虑二维情形如下图&#xff0c;控制力为水平力FFF&#xff0c;输出为角度θ\thetaθ以及小车的位置xxx。 力…...

SpringSecurity支持WebAuthn认证

WebAuthn是无密码身份验证技术&#xff0c;解决了密码泄露的风险&#xff0c;主流的浏览器都支持。有很多开源的类库实现了WebAuthn规范&#xff0c;Java下流行的类库有&#xff1a;webauthn4jjava-webauthn-serververtx-authSpring Security官方暂时未支持WebAuthn&#xff0c…...

深度学习技巧应用3-神经网络中的超参数搜索

大家好&#xff0c;我是微学AI&#xff0c;今天给大家带来深度学习技巧应用3-神经网络中的超参数搜索。 在深度学习任务中&#xff0c;一个算法模型的性能往往受到很多超参数的影响。超参数是指在模型训练之前需要我们手动设定的参数&#xff0c;例如&#xff1a;学习率、正则…...

【信号量机制及应用】

水善利万物而不争&#xff0c;处众人之所恶&#xff0c;故几于道&#x1f4a6; 目录 一、信号量机制 二、信号量的应用 >利用信号量实现进程互斥   >利用信号量实现前驱关系   >利用记录型信号量实现同步 三、例题 四、参考 一、信号量机制 信号量是操作系统提…...

围棋高手郭广昌的“假眼”棋局

&#xff08;图片来源于网络&#xff0c;侵删&#xff09;文丨熔财经作者|易不二2022年&#xff0c;在复星深陷债务压顶和变卖资产漩涡的而立之年&#xff0c;“消失”已久的郭广昌&#xff0c;在质疑与非议声中回国稳定军心&#xff0c;强调复星将在未来的五到十年迎来一个全新…...

23-Oracle 23 ai 区块链表(Blockchain Table)

小伙伴有没有在金融强合规的领域中遇见&#xff0c;必须要保持数据不可变&#xff0c;管理员都无法修改和留痕的要求。比如医疗的电子病历中&#xff0c;影像检查检验结果不可篡改行的&#xff0c;药品追溯过程中数据只可插入无法删除的特性需求&#xff1b;登录日志、修改日志…...

STM32+rt-thread判断是否联网

一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...

使用分级同态加密防御梯度泄漏

抽象 联邦学习 &#xff08;FL&#xff09; 支持跨分布式客户端进行协作模型训练&#xff0c;而无需共享原始数据&#xff0c;这使其成为在互联和自动驾驶汽车 &#xff08;CAV&#xff09; 等领域保护隐私的机器学习的一种很有前途的方法。然而&#xff0c;最近的研究表明&…...

Matlab | matlab常用命令总结

常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...

基于 TAPD 进行项目管理

起因 自己写了个小工具&#xff0c;仓库用的Github。之前在用markdown进行需求管理&#xff0c;现在随着功能的增加&#xff0c;感觉有点难以管理了&#xff0c;所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD&#xff0c;需要提供一个企业名新建一个项目&#…...

Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement

Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement 1. LAB环境2. L2公告策略2.1 部署Death Star2.2 访问服务2.3 部署L2公告策略2.4 服务宣告 3. 可视化 ARP 流量3.1 部署新服务3.2 准备可视化3.3 再次请求 4. 自动IPAM4.1 IPAM Pool4.2 …...

Python竞赛环境搭建全攻略

Python环境搭建竞赛技术文章大纲 竞赛背景与意义 竞赛的目的与价值Python在竞赛中的应用场景环境搭建对竞赛效率的影响 竞赛环境需求分析 常见竞赛类型&#xff08;算法、数据分析、机器学习等&#xff09;不同竞赛对Python版本及库的要求硬件与操作系统的兼容性问题 Pyth…...

上位机开发过程中的设计模式体会(1):工厂方法模式、单例模式和生成器模式

简介 在我的 QT/C 开发工作中&#xff0c;合理运用设计模式极大地提高了代码的可维护性和可扩展性。本文将分享我在实际项目中应用的三种创造型模式&#xff1a;工厂方法模式、单例模式和生成器模式。 1. 工厂模式 (Factory Pattern) 应用场景 在我的 QT 项目中曾经有一个需…...

Python训练营-Day26-函数专题1:函数定义与参数

题目1&#xff1a;计算圆的面积 任务&#xff1a; 编写一个名为 calculate_circle_area 的函数&#xff0c;该函数接收圆的半径 radius 作为参数&#xff0c;并返回圆的面积。圆的面积 π * radius (可以使用 math.pi 作为 π 的值)要求&#xff1a;函数接收一个位置参数 radi…...

怎么开发一个网络协议模块(C语言框架)之(六) ——通用对象池总结(核心)

+---------------------------+ | operEntryTbl[] | ← 操作对象池 (对象数组) +---------------------------+ | 0 | 1 | 2 | ... | N-1 | +---------------------------+↓ 初始化时全部加入 +------------------------+ +-------------------------+ | …...