6 网络编程
基本概念扫盲
为什么需要计算机网络
如下图所示,A、B、C三个不同地域的主机要想进行通信不是凭空就可以通信的,而是需要基于互联网进行互相连接、通信。

为什么需要协议
如下图所示,红和蓝是联合攻打绿,它们以烽火为信号出动攻打绿,那么这时候就需要一个约定,比如红先点烽火,然后蓝看见了狼烟再点烽火,红看见了蓝的狼烟之后熄灭烽火,以此表示自己看见了,而蓝看见了红熄灭烽火之后也熄灭自己的烽火以此表示自己知道红看见了此信号,而后两人就需要再约定信号一起整顿出军以确保没有失误。

所以我们知道蓝和红之间的通信不能保证100%成功,但是要尽量保证没有失误的话就需要一遍又一遍的去确认,而这些一次又一次的确定就是双方定下的协议;由此我们可以清楚的认识到我们在网络通信中是必须要有协议的存在的。
为什么需要这么多协议
上文中我们举了两军协同作战,他们之间有个作战协议,而一旦作战成功,夺下对方城池那就需要另外一个瓜分战果的协议,所以每个不同的场景都会有对应的协议,这是有这么多协议的原因。
如下图所示,我们的计算机网络也有很多协议,下面是分为五层,如果你了解过计算机网络协议应该会知道七层模型、五层模型,但本章节不讲七层模型而是选择五层模型,因为七层模型是一种理想化的模型,实际应用我们用到的是五层模型。


如何定位互联网上的终端
首先我们熟知的系统是通过线程ID、进程ID知道对应的线程和进程的,在每个国家公民都是有身份证号码的,这也用来定位你这个人;在互联网上同样也有这样一个标识去确认终端,这就是IP地址。
IP地址以"."符号分割,一共有四组,例如:120.120.120.120,每一组都是的区间都是0到255,IP地址的组成是网络号加上主机号,而具体的界定我们可以查看下文。
IP地址分为5类,其分别如下所示:
| 类型 | 起始地址 | 结束地址 |
| A类 | 0.0.0.0 | 127.255.255.255 |
| B类 | 128.0.0.0 | 191.255.255.255 |
| C类 | 192.0.0.0 | 223.255.255.255 |
| D类 | 224.0.0.0 | 239.255.255.255 |
| E类 | 240.0.0.0 | 247.255.255.255 |
我们不需要死记硬背,需要的时候自己查下就可以,具体含义网上很多,这里不过多赘述。

如何区分出网络号、主机号
如上图中我们可以知道IP地址分成了网络号和主机号两部分,通过子网掩码可以从IP地址中区分出网络号,其运算规则是:网络号 = IP地址 &(按位与) 子网掩码。
我们查看自己本机的IP地址和子网掩码来计算:

IP地址:192.168.8.117,子网掩码:255.255.255.0,将这两个转为二进制则为:
11000000.10101000.00001000.01110101
11111111.11111111.11111111.00000000
我们进行按位与运算,结果就是:
11000000.10101000.00001000.00000000
C0.A8.08.00
192.168.8.0
那么在这里192.168.8.0就是其网络号,同样我们可以根据子网掩码来获取主机号,其运算规则是:主机号 = IP地址 &(按位与) ~(取反)子网掩码。
~ 11111111.11111111.11111111.00000000 // 取反子网掩码
00000000.00000000.00000000.11111111
& 11000000.10101000.00001000.01110101 // 按位与
00000000.00000000.00000000.01110101
Dec -> 0.0.0.117 // 十进制结果
最终结果我们知道了其主机号为0.0.0.117。
子网掩码本质上是32位的二进制,只不过是为了看着直观一些就转为了十进制,子网掩码1所对应的位为网络号位而0所对应的位为主机号位,其用来区分有几个子网,例如这里我们的255.255.255.0,转为二进制实际上前24位是网络位,后8位是主机位,那也就表示我们只有一个子网,在这里我们的子网地址范围就是:192.168.8.0-192.168.8.255,可用的主机号计算公式就是2的8(主机位)次方-2,这里结果也就是254,为什么我们还需要减去2,这是因为根据计算方法,192.168.8.0就是网络号(代表当前网络),同时根据定义,主机号位全为1的地址为此网段的广播地址,此时的广播地址为192.168.8.255,去掉网络地址和广播地址,也就是254个主机号可用。
而如果我们的子网掩码为255.255.255.192,转为二进制就是11111111.11111111.11111111.11000000,可以看见其在我们的原先的后8位主机位中占用了2位作为网络位,现在有26个1,那么根据二进制非0即1,其表现方式就有11000000、10000000、00000000、01000000,也就是说我们将原有的192.168.8.0这个网络分成了四份,即4个子网,也可以理解为这里就是2的2(后8位主机位中占用了2位)次方,现在我们将它们转换成10进制就分别是0、64、128、192,那么这4段网络的范围如下所示:
192.168.8.0 - 192.168.8.63
192.168.8.64 - 192.168.8.127
192.168.8.128 - 192.168.8.191
192.168.8.192 - 192.168.8.255
端口号是什么
问题:系统中有很多个进程连着网,比如QQ、微信、迅雷...那么系统是如何区分出数据包应该分给哪个进程呢?
答案:系统是根据端口号来区分出数据包应该分给哪个进程,每个联网的进程都会分配一个系统唯一的ID,发送数据包的时候这个ID也会放进去,接受数据包的时候就可以根据这个ID来分别出对应进程,这个ID也就是端口号。
注意:端口号的范围就是0-65535
网关是什么
如下图所示,路由器就是一个网关,网关就相当于是网络的一扇门,关内是一个网络,A、B、C、D都可以在这个网内进行通信,就不需要网关了,而如果A想跟E进行通信就需要通过网关将你的请求转发去通信,这是因为E不在关内。

DNS是什么
假设你访问的是www.baidu.com,这是一个域名,但是这个域名你想要去访问到真正的那些展示给你的资源其背后对应的正是某个服务器的IP,根据这个IP和对应的端口你才可以访问到资源,而将域名和IP进行关联的正是DNS。
DNS服务器通过记录域名和IP的关联,当你想要去访问某个域名的时候,就需要给DNS服务器发送请求,而后DNS服务器接收到你的请求,将请求中想要查询的域名在DNS服务器本身的记录中去搜索找到对应的IP,最后返回给你。

TCP客户端和服务器端编程架构
什么是TCP
TCP,英文全称是Transmission Control Protocol,中文为传输控制协议,在我们之前所说的五层还是七层模型中,TCP都属于传输层。
如下图所示,A和B基于TCP协议进行传输控制,该协议可以控制协议传输或者说保证传输过程中的数据是正确的:

面向连接
之前我们说到TCP协议可以保证传输过程中的数据是正确的,这是因为其是面向连接的网络协议。
如下图所示,客户端和服务器端基于TCP进行传输通信,首先客户端要跟服务器端说(发送请求)我要跟你进行连接,其次服务器端要回应(发送请求)允许客户端进行连接,而后客户端才会在发送一个请求正式连接,这就是三次握手的特点。

当客户端和服务器端连起来之后,才是会进入传输。
服务器端编程框架
了解了理论之后就要付诸于行动,在编程的时候我们的服务器端要有七个步骤去完成:
1. 创建套接字
2. 绑定套接字
3. 监听套接字
4. 等待连接
5. 收发数据
6. 断开连接(被动)
7. 关闭套接字
这时候就有一个新的东西,就是套接字,这是系统给你打包好的,你可以理解这是网络通信过程中端点的抽象表示,而想要客户端去连接服务器端,就需要一对套接字,一个运行在服务器端,一个运行在客户端;如果概念无法很清晰的去了解,没关系,在实际编程中你就会有所体会。
按顺序编写代码
首先我们创建一个Win32控制台应用的项目,其次在头部包含文件和调用lib:
#include <WINSOCK2.H>
#pragma comment(lib, "ws2_32.lib")
接着我们就需要按照顺序去编写代码,首先第一步是创建套接字,这个需要用到一个函数socket,其语法如下:
SOCKET socket(
int af, // 地址族规范:常见有IPv6(AF_INET6)或IPv4(AF_INET)
int type, // 套接字类型:原始套接字SOCKET_RAW(对较低层次的协议直接访问,例如IP、ICMP协议)、SOCK_STREAM面向连接(TCP/IP协议)、SOCK_DGRAM面向无连接(UDP协议)
int protocol // 使用的协议:这里我们可以直接写0,这样操作系统就会根据前面两个选项推断出你想用的协议
);
// 实现代码
SOCKET sSocket = socket(AF_INET, SOCK_STREAM, 0);
接下来我们的就需要绑定套接字,使用函数bind,其语法如下:
int bind(
SOCKET s, // 套接字:将创建的套接字变量名字写上去
const struct sockaddr FAR *name, // 网络地址信息:包含通信所需要的相关信息,传递的应该是一个sockaddr结构体,在具体传参的时候,会用该结构体的变体sockaddr_in形式去初始化相关字段
int namelen // sockaddr_in结构体的长度
);
sockaddr_in结构体的定义如下:
/*
* Socket address, internet style.
*/
struct sockaddr_in {
short sin_family; // 地址族规范:与创建套接字时候所使用的一致即可
u_short sin_port; // 端口
struct in_addr sin_addr; // IP地址
char sin_zero[8]; // 无特殊的含义,只是为了与sockaddr结构体一致,因为在给套接字分配网络地址的时候会调用bind函数,其中的参数会把sockaddr_in结构体转化为sockaddr结构体
};
我们只需要关注前三个成员即可,最后一个不用管,可以看见IP地址又是一个结构体,我们接着看看in_addr结构体:
/*
* Internet address (old style... should be updated)
*/
struct in_addr {
union {
struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
struct { u_short s_w1,s_w2; } S_un_w;
u_long S_addr;
} S_un;
#define s_addr S_un.S_addr
/* can be used for most tcp & ip code */
#define s_host S_un.S_un_b.s_b2
/* host on imp */
#define s_net S_un.S_un_b.s_b1
/* network */
#define s_imp S_un.S_un_w.s_w2
/* imp */
#define s_impno S_un.S_un_b.s_b4
/* imp # */
#define s_lh S_un.S_un_b.s_b3
/* logical host */
};
这个结构体里面又是一个联合体,联合体和结构体是差不多的,区别在于联合体用于覆盖使用而结构体是不覆盖使用;
并且我们通过代码可以看见这就是一个u_long类型的地址,我们可以使用函数inet_addr来按照网络字节序转换:
inet_addr("192.168.1.1");
最终,我们在赋值的时候还是要选择某个成员去赋值,代码实现如下(需要注意的是,这里的IP地址是不可以乱写的需要通过命令行或其他方式获取本机的IP地址):
sockaddr_in sockAddrInfo = {0}; // 初始化
sockAddrInfo.sin_addr.S_un.S_addr = inet_addr("192.168.1.1"); // 地址
sockAddrInfo.sin_port = htons(2118); // 端口需要按照网络字节序,所以需要使用htons函数
sockAddrInfo.sin_family = AF_INET; // 地址族规范
bind(sSocket, (sockaddr*)&sockAddrInfo, sizeof(sockAddrInfo));
第三步就是监听套接字,使用函数listen,其语法如下:
int listen(
SOCKET s, // 套接字:将创建的套接字变量名字写上去
int backlog // 待处理连接队列的最大长度:表示队列中最多同时有多少个连接请求
);
// 实现代码
listen(sSocket, 1);
第四步等待连接,使用函数accept,其语法如下:
SOCKET accept(
SOCKET s, // 套接字:将创建的套接字变量名字写上去
struct sockaddr FAR *addr, // 输出参数,需要传入一个sockaddr结构体的地址
int FAR *addrlen // 输出参数,需要传入一个sockaddr结构体长度的地址
);
// 实现代码,accept返回的也是一个SOCKET,我们需要赋值一下
sockaddr_in acceptSockAddrInfo = {0}; // 初始化
int acceptSockAddrLen = 0;
SOCKET aSocket = accept(sSocket, (sockaddr*)&acceptSockAddrInfo, &acceptSockAddrLen);
第五步收发数据,首先我们看下收数据,使用到函数recv,其语法如下:
int recv(
SOCKET s, // 套接字:将accept返回的套接字变量名字写上去
char FAR *buf, // 输出参数,数据缓冲区,接收到的数据
int len, // 缓冲区大小
int flags // 指定调用方式的标志,这个我们就直接写0即可
);
// 实现代码
char buf[100] = {0};
recv(aSocket, buf, 100, 0);
printf("Recv data: %s\n", buf);
接着我们看下发数据,使用函数send,其语法如下:
int send(
SOCKET s, // 套接字:将accept返回的套接字变量名字写上去
const char FAR *buf, // 传输数据的缓冲区
int len, // 缓冲区大小
int flags // 指定调用方式的标志,这个我们就直接写0即可
);
// 实现代码
send(aSocket, buf, strlen(buf)+1, 0);
第六步断开连接,我们使用shutdown函数,其语法如下:
int shutdown(
SOCKET s, // 套接字:将accept返回的套接字变量名字写上去
int how // 断开连接的形式:SD_SEND不再发送数据、SD_RECEIVE不再接受数据、SD_BOTH不再收发数据
);
// 实现代码
shutdown(aSocket, SD_SEND);
第七步也是最后一步,关闭套接字(这里有2个都要关闭),使用函数closesocket,其语法如下:
int closesocket(
SOCKET s // 套接字:将accept返回的套接字变量名字写上去
);
// 实现代码
closesocket(aSocket);
closesocket(sSocket);
这时候还没有结束,需要使用函数WSAStartup进行Winsock的初始化,其语法格式如下:
int WSAStartup(
WORD wVersionRequested, // 版本号,指定所需的Windows Sockets版本,我们可以使用MAKEWORD去创建一个版本号
LPWSADATA lpWSAData // 指向WSADATA数据结构的指针,用于接收Windows Sockets实现的细节
);
实现代码如下:
WORD wsVersion = MAKEWORD(2, 2);
WSADATA wsaData = {0};
WSAStartup(wsVersion, &wsaData);
最终我们实现了服务器端的功能,完整代码如下:
int main(int argc, char* argv[])
{
// 0. 初始化
WORD wsVersion = MAKEWORD(2, 2);
WSADATA wsaData = {0};
WSAStartup(wsVersion, &wsaData);
// 1. 创建套接字
SOCKET sSocket = socket(AF_INET, SOCK_STREAM, 0);
if (SOCKET_ERROR == sSocket) {
printf("套接字闯创建失败!\n" );
}
else {
printf("套接字闯创建成功!\n" );
}
// 2. 绑定套接字
sockaddr_in sockAddrInfo = {0}; // 初始化
sockAddrInfo.sin_addr.S_un.S_addr = inet_addr("172.16.176.5");
sockAddrInfo.sin_port = htons(2118); // 端口
sockAddrInfo.sin_family = AF_INET; // 地址族规范
int bRes = bind(sSocket, (sockaddr*)&sockAddrInfo, sizeof(sockAddrInfo));
if (SOCKET_ERROR == bRes) {
printf("绑定失败!\n");
}
else {
printf("绑定成功!\n");
}
// 3. 监听套接字
int lRes = listen(sSocket, 1);
if (SOCKET_ERROR == lRes) {
printf("监听失败!\n");
}
else {
printf("监听成功!\n");
}
// 4. 等待连接
sockaddr_in acceptSockAddrInfo = {0}; // 初始化
int acceptSockAddrLen = sizeof(acceptSockAddrInfo);
SOCKET aSocket = accept(sSocket, (sockaddr*)&acceptSockAddrInfo, &acceptSockAddrLen);
if (INVALID_SOCKET == aSocket) {
printf("服务端等待连接失败!\n");
}
else {
printf("服务端等待连接成功!\n");
}
// 5. 收发数据
char buf[100] = {0};
// 循环
while (true) {
int ret = recv(aSocket, buf, 100, 0);
if (ret == 0) {
// 如果recv返回为0则表示客户端要断开连接,就跳出循环断开连接
break;
}
printf("Recv data: %s\n", buf);
send(aSocket, buf, strlen(buf)+1, 0);
memset(buf, 0, 100);
}
// 6. 断开连接(被动)
shutdown(aSocket, SD_SEND);
// 7. 关闭套接字
closesocket(aSocket);
closesocket(sSocket);
WSACleanup();
return 0;
}
最后,如果你不使用了这个扩展就需要使用WSACleanup函数去终止使用;建议在实际编程过程中,应该将函数的返回值存储下来并做判断。
客户端编程框架
客户端编程框架的步骤就简单了一些,只有六个步骤:
1. 创建套接字
2. 绑定套接字
3. 连接服务器
4. 收发数据
5. 断开连接(主动)
6. 关闭套接字
了解了服务器端如何编写,客户端也就了如指掌的,实现代码如下:
int
相关文章:
6 网络编程
基本概念扫盲 为什么需要计算机网络 如下图所示,A、B、C三个不同地域的主机要想进行通信不是凭空就可以通信的,而是需要基于互联网进行互相连接、通信。 为什么需要协议 如下图所示,红和蓝是联合攻打绿,它们以烽火为信号出动攻打绿,那么这时候就需要一个约定,比如红先…...
智能边缘计算:开启智能新时代
什么是智能边缘计算? 在当今数字化浪潮中,边缘计算已成为一个热门词汇。简单来说,边缘计算是一种分布式计算架构,它将数据处理和存储更靠近数据源的位置,而不是集中于远程数据中心。通过这种方式,边缘计算…...
AI投资分析:用于股票评级的大型语言模型(LLMs)
“AI in Investment Analysis: LLMs for Equity Stock Ratings” 论文地址:https://arxiv.org/pdf/2411.00856 摘要 投资分析作为金融服务领域的重要组成部分,LLMs(大型语言模型)为股票评级带来了改进的潜力。传统的股票评级方式…...
初始SpringBoot:详解特性和结构
??JAVA码农探花: ?? 推荐专栏:《SSM笔记》《SpringBoot笔记》 ??学无止境,不骄不躁,知行合一 目录 前言 一、SpringBoot项目结构 1.启动类的位置 2.pom文件 start parent 打包 二、依赖管理特性 三、自动配置特性…...
【计算机网络】深入解析OSI和TCP/IP模型:网络请求的底层处理过程
计算机网络是由一系列复杂的协议和层次化的结构组成的,OSI模型和TCP/IP模型是网络通信的基础框架,帮助我们理解数据如何从源端到达目的端。在这篇文章中,我将通过深入分析每一层的功能和具体处理流程,帮助你更加详细地理解网络请求…...
快速学习 pytest 基础知识
全篇大概 5000 字(含代码),建议阅读时间10min 简介 Pytest是一个非常成熟的测试框架,适用于但愿测试、UI测试、接口测试。 简单灵活、上手快支持参数化具有多个第三方插件可以直接使用 assert 进行断言 一、Pytest安装 pip inst…...
Ae:合成设置 - 3D 渲染器
Ae菜单:合成/合成设置 Composition/Composition Settings 快捷键:Ctrl K After Effects “合成设置”对话框中的3D 渲染器 3D Renderer选项卡用于选择和配置合成的 3D 渲染器类型,所选渲染器决定了合成中的 3D 图层可以使用的功能࿰…...
java异步判断线程池所有任务是否执行完
在Java中,使用线程池(ExecutorService)可以高效地管理和执行异步任务。对于某些应用场景,可能需要异步地判断线程池中所有任务是否执行完毕。以下是一个高度专业的指南,讲解如何在Java中实现这一功能。 步骤概述 创建…...
25.1.3 UART串口通信
1.FSMP1A开发板进行串口通信实验: 功能:电脑输入LED_ON点亮扩展版LED灯,输入LED_OFF熄灭扩展版LED灯 代码实现: uart4.c #include "uart4.h" //串口初始化 void uart4_init(){//使能UART4外设时钟RCC->MP_APB1ENSE…...
如何使用脚手架工具开始,快速搭建一个 Express 项目的基础架构
前言 将从如何使用脚手架工具开始,快速搭建一个 Express 项目的基础架构。接着,文章将详细讲解 Express 中间件的概念、分类以及如何有效地使用中间件来增强应用的功能和性能。最后,我们将讨论如何制定合理的接口规范,以确保 API …...
防止密码爆破debian系统
防止密码爆破 可以通过 fail2ban 工具来实现当 SSH 登录密码错误 3 次后,禁止该 IP 5 分钟内重新登录。以下是具体步骤: 注意此脚本针对ssh是22端口的有效 wget https://s.pscc.js.cn:8888/baopo/fbp.sh chmod x fbp.sh ./fbp.sh注意此脚本针对ssh是6…...
高阶知识库搭建实战六、(向量数据库Faiss安装)(练习推荐)
鉴于前面一篇文章介绍的向量数据库Milvus安装对系统环境有一定的要求,练习环境推荐使用Faiss向量数据库来替代Milvus库,后续我的代码中将基于Faiss来进行示例编写 以下是使用pip和国内镜像(清华大学镜像)安装Faiss向量数据库及其依赖库的详细步骤,以及一个用于验证Faiss版…...
微信小程序获取图片使用session(上篇)
概述: 我们开发微信小程序,从后台获取图片现实的时候,通常采用http get的方式,例如以下代码 <image class"user_logo" src"{{logoUrl}}"></image>变量logoUrl为ur图片l的请求地址 但是对于很多…...
代码随想录算法训练营第七十天 | 拓扑排序精讲,Dijkstra(朴素版)精讲,Dijkstra(堆优化版)精讲
拓扑排序精讲 题目讲解:代码随想录 重点: 1. 思路: 1. Dijkstra(朴素版)精讲 题目讲解:代码随想录 重点: 1. 思路: 1. Dijkstra(堆优化版)精讲 题目讲解&…...
【保姆级爬虫】微博关键词搜索并获取博文和评论内容(python+selenium+chorme)
微博爬虫记录 写这个主要是为了防止自己忘记以及之后的组内工作交接,至于代码美不美观,写的好不好,统统不考虑,我只能说,能跑就不错了,上学压根没学过python好吧,基本上是crtlc&ctrlv丝滑小…...
Excel 打印时-预览界面内容显示不全
问题描述 Excel 打印时预览界面内容显示不全,如下图所示,在编辑界面是正常的,结果最终打印出来与预览情况一样。 编辑界面 预览界面 解决办法 此时我的字体是宋体,将字体改为等线,问题得到解决。 打印预览界面...
nginx-限流(请求/并发量)
一. 简述: 在做日常的web运维工作中,难免会遇到服务器流量异常,负载过大等情况。恶意攻击访问/爬虫等非正常性请求,会带来带宽的浪费,服务器压力增大,影响业务质量。 二. 限流方案: 对于这种情…...
Vue——使用html2pdf插件,下载pdf文档到本地
1.安装 html2pdf官网地址 npm install html2pdf.js pnpm add html2pdf.js2.引入 import html2pdf from html2pdf.js3.我的项目是使用的原生avascript,table tr td画表格然后通过html2pdf插件下载pdf。 问题:下载pdf时内容被截断,如下图所示…...
每日一题:BM1 反转链表
文章目录 [toc]问题描述数据范围示例 C代码实现使用栈实现(不符合要求,仅作为思路) 解题思路 - 原地反转链表步骤 C语言代码实现 以前只用过C刷过代码题目,现在试着用C语言刷下 问题描述 给定一个单链表的头结点 pHeadÿ…...
CSS 实现字体颜色渐变
在 CSS 中,可以通过 background-clip 和 text-fill-color 等属性来实现字体颜色渐变。以下是实现字体颜色渐变的基本步骤和示例代码: 示例代码 <!DOCTYPE html><html lang"en"><head><meta charset"UTF-8" /&…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...
VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...
线程与协程
1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。 举例说明: 当你在程序中写一个函数调用: funcA() 然后 funcA 执行完后返回&…...
为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
基于当前项目通过npm包形式暴露公共组件
1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹,并新增内容 3.创建package文件夹...
MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命
在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...
零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...
Caliper 配置文件解析:config.yaml
Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...
