从进程的视角来看,网络通信就是一个主机上的进程和另外一个主机上的进程进行信息传递,因此对于操作系统而言,网络通信就是一种进程间通信的方式。

不过这种进程间通信有特殊之处:同一台主机下可以通过进程ID来标识一个唯一的进程,两个进程通过进程ID来相互识别,可是对于不同主机上的两个进程而言,知道对方进程ID并没有什么意义,因此需要另外一种方式来相互识别:IP+端口号(port)

其中IP用于在局域网内确定唯一一台主机,而规定一个端口号只能被一个进程占用,通过IP+端口号的方式,两个进程就能识别对方并进行通信。

端口号

1.是传输层协议的内容,用来标识一台主机中的进程

2.是一个2字节,16比特位的整数

3.一个端口号只能被一个进程占用,一个进程可以占用多个端口号

4.IP地址+端口号能够表示网络上的某台主机的一个进程

端口号范围

0 - 1023: 知名端口号, HTTP, FTP, SSH 等这些广为使用的应用层协议, 他们的端口号都是固定的.

1024 - 65535: 操作系统动态分配的端口号. 客户端程序的端口号, 就是由操作系统从这个范围分配的.

Socket API

操作系统将网络通信抽象为 Socket(套接字),socket是一个五元组标识, 完整定义为:

[协议, 源IP, 源Port, 目标IP, 目标Port](例如 [TCP, 192.168.1.2:54321, 93.184.216.34:80])。

在Linux下,socket通过一个文件描述符sockfd来进行描述和管理,每个sockfd对应一个socket,进而对应一个IP+port,由于每个进程有独立的文件描述符表,这使得该文件描述符sockfd被一个进程独享,印证了上文IP+Port确定一台主机上的唯一进程,这同时意味着我们可以用文件IO的方式来进行网络通信,当然这里我们还是循序渐进,先来介绍socket的相关接口:

socket主要接口依赖于头文件:

#include <sys/socket.h>

创建一个sockfd:

int socket(int domain, int type, int protocol);

domain: 指定通信协议族,例如: AF_INET: IPv4 网络协议。 AF_INET6: IPv6 网络协议。 AF_UNIX: 本地进程间通信。

type: 指定套接字类型,例如: SOCK_STREAM: 面向连接的流式套接字(如 TCP)。 SOCK_DGRAM: 无连接的数据报套接字(如 UDP)。 SOCK_RAW: 原始套接字,用于底层协议访问(不常用)。

protocol: 指定具体协议,通常设置为 0,表示使用默认协议。例如: 对于 SOCK_STREAM,默认是 TCP。 对于 SOCK_DGRAM,默认是 UDP。

返回值为sockfd

将一个sockfd与一个端口号进行绑定 

int bind(int socket, const struct sockaddr *address,socklen_t address_len);

(1)参数 sockfd ,需要绑定的socket。

(2)参数 addr ,一个存放目的地址和目的端口号的结构体,需要进行初始化。

(3)参数 addrlen ,表示 addr 结构体的大小

(4)返回值:成功则返回0 ,失败返回-1,错误原因存于 errno 中。如果绑定的地址错误,或者端口已被占用,bind 函数一定会报错,否则一般不会返回错误。

sockaddr

这个sock_addr就是内核态中的socket从用户态中获取地址族和目标IP+port的方式:

struct sockaddr 
{  sa_family_t sin_family;//地址族char sa_data[14]; //14字节,包含套接字中的目标地址和端口信息               
}; 

不难发现该数据结构有一个缺陷:端口号和ip地址混在一块了,这明显不方便我们进行初始化

为了解决此问题,又定义了sockaddr_in,依赖于头文件:

#include<netinet/in.h>

所以实践中,我们会先定义一个sockaddr_in来完成初始化,再将其指针强转为sockaddr*用于绑定

这里还有一个十分重要的细节问题:网络字节序

sin_port和sin_addr都必须是网络字节序(大端模式,低地址高字节),一般可视化的数字都是主机字节序(小端模式,低地址低字节)。

这里用一个简单的例子来帮助理解:

对于数据 0x12345678,假设从地址0x4000开始存放,在大端和小端模式下,存放的位置分别为:

总之,我们给sin_port和sin_addr进行初始化时,要进行字节序的转换,这里需要用到两个函数:

htons()作用是将端口号由主机字节序转换为网络字节序的整数值。(host to net)

inet_addr()作用是将一个IP字符串转化为一个网络字节序的整数值,用于sockaddr_in.sin_addr.s_addr。

需要头文件:

#include <arpa/inet.h>

是不是有些复杂,我们实际演示一下:

创建并绑定一个UDP协议的socket:

int port=8080;
char ip[16]=192.168.1.0;int server_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (server_fd < 0) 
{perror("socket creation failed");return 1;
}struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(ip);
//推荐这么写:
//server_add.sin_addr.s_addr=htonl(INADDR_ANY);
server_addr.sin_port = htons(port); if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) 
{perror("bind failed");close(server_fd);return 1;
}

上述接口是UDP和TCP公用的,下面先介绍一下这两个协议的特点,再分别介绍各自的接口

UDP

核心思想: “尽最大努力交付” (Best Effort)。简单、快速、无连接。

关键特性:

无连接: 发送数据之前不需要预先建立连接。每个数据包(称为数据报)都是独立处理的。

不可靠 : 不保证数据报一定能到达目的地,不保证按发送顺序到达,也不保证数据报只到达一次。可能发生丢失、重复、乱序。

面向报文: 对应用层交下来的报文,添加 UDP 首部后就直接交给网络层 IP。接收方 UDP 对 IP 层交上来的 UDP 数据报,去除首部后就原封不动地交付给上层应用进程。应用程序需要自己处理报文边界。

无拥塞控制: UDP 本身不会根据网络状况调整发送速率。如果发送太快导致网络拥堵,UDP 包会被大量丢弃,但它本身不会主动慢下来。

首部开销小: UDP 首部固定为 8 字节。

支持单播、多播、广播: 非常灵活。

缓冲区

UDP 没有真正意义上的发送缓冲区,调用 sendto 会直接交给内核, 由内核将数 据传给网络层协议进行后续的传输动作;

UDP 具有接收缓冲区,但是这个接收缓冲区不能保证收到的 UDP 报的顺序和发送 UDP 报的顺序一致;

如果缓冲区满了, 再到达的 UDP 数据就会被丢弃;

UDP 的 socket 既能读, 也能写, 这个概念叫做全双工

UDP报头

UDP在内核中通过sk_buff进行管理,其中有一个指向报文起始位置的指针data,由于UDP的报头是固定长度8B,所以只需将data指针移动8B即可

UDP虽然不可靠,但是会保证内容的正确性,其中UDP校验和就是一种检验UDP数据包是否有误的校验机制,它通过某种算法将UDP数据包中的所有数据进行计算然后存储在报头字段中,以便确保接收方在收到数据包后进行校验。如果校验失败的话,就直接把这个数据包丢弃

我们注意到, UDP协议首部中有一个16位的最大长度. 也就是说一个UDP能传输的数据最大长度是64K(包含UDP首部).   然而64K在当今的互联网环境下, 是一个非常小的数字.如果我们需要传输的数据超过64k,就需要在应用层手动的分包, 多次发送并在接收端手动拼装(面向数据报) 

send和recvfrom

由于UDP传输数据是面向报文的,因此我们不能直接用面向字节流的文件IO接口,而是需要使用函数recvfrom()来接收数据,使用send()来发送数据

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
  1. 第一个参数sockfd:正在监听端口的套接口文件描述符,通过socket获得
  2. 第二个参数buf:接收缓冲区,往往是使用者定义的数组,该数组装有接收到的数据
  3. 第三个参数len:接收缓冲区的大小,单位是字节
  4. 第四个参数flags:填0即可
  5. 第五个参数src_addr:指向发送数据的主机地址信息的结构体,也就是我们可以从该参数获取到数据是谁发出的
  6. 第六个参数addrlen:表示第五个参数所指向内容的长度
  7. 返回值:成功:返回接收成功的数据长度
  8. 失败: -1
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
  1. 第一个参数sockfd:正在监听端口的套接口文件描述符,通过socket获得
  2. 第二个参数buf:发送缓冲区,往往是使用者定义的数组,该数组装有要发送的数据
  3. 第三个参数len:发送缓冲区的大小,单位是字节
  4. 第四个参数flags:填0即可
  5. 第五个参数dest_addr:指向接收数据的主机地址信息的结构体,也就是该参数指定数据要发送到哪个主机哪个进程
  6. 第六个参数addrlen:表示第五个参数所指向内容的长度
  7. 返回值:成功:返回发送成功的数据长度
  8. 失败: -1

通过UDP协议进行通信的流程如下:

下面我们对上述内容进行一个小实践,实现一个客户端的本地回显

目标:客户端向服务端发送内容,服务器将这些内容再发给客户端,客户端打印接收到的内容

客户端

#include<iostream>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<string.h>int main(int argc,char* argv[])
{std::string server_ip=argv[1];uint16_t server_port=std::stoi(argv[2]);int sockfd=socket(AF_INET,SOCK_DGRAM,0);if(sockfd<0){std::cout<<"创建套接字失败\n";}sockaddr_in server;memset(&server,0,sizeof(server));server.sin_family=AF_INET;server.sin_port=htons(server_port);server.sin_addr.s_addr=inet_addr(server_ip.c_str());while(true){std::cout<<"请输入:";std::string line;std::getline(std::cin,line);sendto(sockfd,line.c_str(),line.size(),0,(sockaddr*)&server,sizeof(server));sockaddr_in tmp;socklen_t len=sizeof(tmp);char buffer[1024]={0};int ret=recvfrom(sockfd,buffer,sizeof(buffer)-1,0,(sockaddr*)&tmp,&len);if(ret>0){buffer[ret]=0;std::cout<<buffer<<'\n';}}
}

服务端.hpp

#include"Log.h"
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<strings.h>static const int gdefaultsockfd=-1;class UdpServer
{
public:UdpServer(std::string& ip,uint16_t port):sockfd(gdefaultsockfd),ip(ip),port(port){}~UdpServer()=default;void init(){sockfd=socket(AF_INET,SOCK_DGRAM,0);if(sockfd<0){LOG(LogLevel::FATAL)<<"创建套接字失败";exit(1);}LOG(LogLevel::INFO)<<"创建套接字成功";sockaddr_in local;bzero(&local,sizeof(local));local.sin_family=AF_INET;local.sin_port=htons(port);local.sin_addr.s_addr=inet_addr(ip.c_str());int n=bind(sockfd,(sockaddr*)&local,sizeof(local));if(n<0){LOG(LogLevel::FATAL)<<"套接字绑定失败";exit(2);}LOG(LogLevel::INFO)<<"套接字绑定成功";}void start(){is_running=true;while(is_running){char buffer[1024];buffer[0]=0;sockaddr_in  peer;socklen_t len=sizeof(peer);ssize_t n=recvfrom(sockfd,buffer,sizeof(buffer),0,(sockaddr*)&peer,&len);if(n>0){buffer[n]=0;std::string echo="server echo#";echo+=buffer;sendto(sockfd,echo.c_str(),echo.size(),0,(sockaddr*)&peer,len);}}}void stop(){is_running=false;}
private:int sockfd;//套接字文件描述符uint16_t port;//端口号std::string ip;//ip地址bool is_running=false;
};

服务端.cc

#include"udp_server.hpp"
#include<memory>int main(int argc,char* argv[])
{std::string ip=argv[1];uint16_t port=std::stoi(argv[2]);std::unique_ptr<UdpServer> udp_server=std::make_unique<UdpServer>(ip,port);udp_server->init();udp_server->start();return 0;
}

分别启动客户端和服务端:

服务端

客户端

测试成功

TCP

Tcp的特性相对于udp较为复杂,因此我们本次只会进行概括性地描述并介绍几个接口:

有连接,需要客户端向服务的发起连接请求

可靠传输

面向字节流

监听客户端的连接请求

int listen(int sockfd, int backlog);
  • 功能:将套接字设置为监听状态,准备接受客户端的连接请求。
  • 参数:
    • sockfd:已绑定的套接字描述符。
    • backlog:指定等待连接队列的最大长度。
  • 返回值:成功返回 0,失败返回 -1。

连接

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • 参数:
    • sockfd:套接字描述符。
    • addr:指向服务器的地址结构体。
    • addrlenaddr 结构体的长度。
  • 返回值:成功返回 0,失败返回 -1。

从已完成连接队列中取出一个连接,并创建一个新的套接字与客户端进行通信

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
  • 参数:
    • sockfd:监听套接字描述符。
    • addr:用于存储客户端的地址信息。
    • addrlen:用于指定 addr 结构体的长度。
  • 返回值:成功返回一个新的套接字描述符用于与客户端通信,失败返回 -1。

你可能会疑惑我不是已经通过socket创建了一个sockfd吗,为什么这里还要创建新的sockfd,其实对于Tcp而言,socket创建的sockfd只是用于接收用户连接请求的,而真正与用户通信则是通过accept创建的sockfd进行的,这是因为Tcp通信只能一对一进行,即一个端到端通信占用一个sockfd,要想实现一个服务端与多个客户端进行通信,就需要建立多个sockfd

而由于Tcp是面向字节流进行传输的,因此我们可以直接使用文件IO的接口来读取和写入数据

下面是Tcp版本的客户端回显:

服务端

#include"inet_addr.hpp"
#include"Log.h"
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<strings.h>static const int gdefaultsockfd=-1;
static const int gbacklog=8;class TcpServer
{
public:TcpServer(std::string& ip,uint16_t port=8080):sockfd(gdefaultsockfd),ip(ip),port(port){}~TcpServer()=default;void init(){sockfd=socket(AF_INET,SOCK_STREAM,0);if(sockfd<0){LOG(LogLevel::FATAL)<<"创建套接字失败";exit(1);}LOG(LogLevel::INFO)<<"创建套接字成功";InetAddr local(port);int n=bind(sockfd,local.Addr(),local.Length());if(n<0){LOG(LogLevel::FATAL)<<"套接字绑定失败";exit(2);}LOG(LogLevel::INFO)<<"套接字绑定成功";if(listen(sockfd,gbacklog)!=0){LOG(LogLevel::FATAL)<<"监听套接字失败";exit(3);}}void start(){is_running=true;while(is_running){sockaddr_in  peer;socklen_t len=sizeof(peer);int sock_fd=accept(sockfd,(sockaddr*)&peer,&len);        if(sock_fd<0){LOG(LogLevel::FATAL)<<"接收失败";}InetAddr clientaddr(peer);HandlerIO(sock_fd,clientaddr);}}void stop(){is_running=false;}
private:void HandlerIO(int fd,InetAddr& client){char buffer[1024];while(true){buffer[0]=0;auto n=read(fd,buffer,sizeof(buffer)-1);if(n>0){buffer[n]=0;std::string echo_string = "server echo: ";echo_string += buffer;LOG(LogLevel::INFO) << buffer;auto m = write(fd,echo_string.c_str(),echo_string.size());}}close(fd);}private:int sockfd;//套接字文件描述符uint16_t port;//端口号std::string ip;//ip地址bool is_running=false;
};

客户端

#include"inet_addr.hpp"
#include<iostream>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<string.h>
#include<unistd.h>int main(int argc,char* argv[])
{std::string server_ip=argv[1];uint16_t server_port=std::stoi(argv[2]);int sockfd=socket(AF_INET,SOCK_STREAM,0);if(sockfd<0){std::cerr<<"创建套接字失败\n";exit(1);}InetAddr server(server_port,server_ip);if(connect(sockfd,server.Addr(),server.Length())!=0){std::cerr<<"连接失败\n";exit(2);}while(true){std::cout<<"请输入:";std::string line;std::getline(std::cin,line);auto n=write(sockfd,line.c_str(),line.size());if(n>=0){char buffer[1024];auto m=read(sockfd,buffer,sizeof(buffer)-1);if(m>0){buffer[m]=0;std::cout<<buffer<<'\n';}}}
}

启动服务端

启动客户端

测试成功

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android init.rc详解3

关于Android Init的详解&#xff0c;关于Action&#xff0c;Service&#xff0c;Trigger的请参考Android init.rc详解1&#xff0c;关于Options的请参考Android init.rc详解2&#xff0c;本章将介绍常见的Commands。 1 Commands bootchart [start|stop] 启动或停止bootcharti…

Sentinel原理之规则管理

文章目录1. 基础知识2. 数据源使用2.1 RedisDatasource2.2 ZookeeperDatasource1. 基础知识 流量控制规则&#xff08;FlowRule&#xff09;&#xff1a; 阈值类型grade&#xff1a; 0&#xff08;并发线程数&#xff09;&#xff1a;限制同时处理请求的线程1&#xff08;QPS…

系统时钟配置

STM32F103C8T6的系统时钟配置成72MHZ1. 什么是 STM32 系统时钟系统时钟&#xff08;System Clock&#xff09;是整个 MCU&#xff08;微控制器&#xff09;运行的“节拍信号”&#xff0c;所有 CPU 指令执行、外设操作、定时器计时、总线数据传输等&#xff0c;都依赖这个时钟频…

Al大模型-本地私有化部署大模型-大模型微调

魔塔社区 魔塔社区平台介绍 https://www.modelscope.cn/models/Qwen/Qwen2.5-0.5B-Instruct 申请免费的试用机器 如果自己没有机器 &#xff0c;从这里申请机器 。 下载大模型 pip install modelscope 下载到当前目录 mkdir -p /root/autodl-tmp/demo/Qwen/Qwen2.5-0.5B-Ins…

国内著名AI搜索优化专家孟庆涛发表《AI搜索内容可信度评估综合指南》

近日&#xff0c;国内著名AI搜索优化专家、中国GEO生成式引擎优化领域的开拓者与实践专家孟庆涛正式发布《AI搜索内容可信度评估综合指南》&#xff0c;针对当前AI生成内容&#xff08;AIGC&#xff09;在搜索场景中可信度参差不齐的痛点&#xff0c;首次提出覆盖"技术-内…

ruoyi-flowable系统防xss攻击配置(使用富文本的方式)

背景。开发小程序过程中。用户使用富文本的方式比较多。但在传输后发现如上传到系统中的图片链接地址被清空了。问题&#xff1a;想要使用富文本。还需要开启xss过滤。有什么好的解决方案吗&#xff1f;解决方案&#xff08;我比较倾向的&#xff09;&#xff1a;通过对富文本内…

【opencv-Python学习笔记(2): 图像表示;图像通道分割;图像通道合并;图像属性】

目标&#xff1a;1.学会图像的通道分割与合并2.学会图像的的常规操作##一些概念&#xff1a;二值图像&#xff1a;只包含黑色和白色两种颜色的图像&#xff0c;1为白色&#xff0c;0为黑色灰度图像&#xff1a;计算机会将灰度处理为256个灰度级&#xff0c;用区间[0,255]来表示…

Qt——常用Widget(控件)

常用控件 Widget 需要说明&#xff0c;此处说明的控件都继承于QWiget&#xff0c;因此之前所说的控件属性&#xff0c;和相关API&#xff0c;在这里的控件都适用 文章目录常用控件 Widget按钮类控件QPushButtonQRadioButtonQCheckBox显示类控件QLabel初识事件LCD NumberProgre…

Cursor/VSCode/VS2017 搭建Cocos2d-x环境,并进行正常的调试和运行(简单明了)

作者&#xff1a;求一个demo 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 内容通俗易懂&#xff0c;没有废话 废话不多说&#xff0c;我们直接开始------>>>>>> &#xff01;&#xff…

从 LLM 到自主 Agent:OpenCSG 打造开源 AgenticOps 生态

从 LLM 到自主 Agent&#xff1a;OpenCSG 打造开源 AgenticOps 生态在产业拐点上&#xff0c;交付可持续、可落地的智能体未来在生成式 AI 的时代洪流中&#xff0c;大语言模型&#xff08;LLM&#xff09;已成为行业标配&#xff0c;但如何突破“会说不会做”的局限&#xff0…

黑马程序员mysql课程中在Linux系统中安装mysql出现问题

问题描述在安装linux的最后一步的指令的时候报错警告&#xff1a;mysql-community-server-8.0.26-1.el7.x86_64.rpm: 头V3 DSA/SHA256 Signature, 密钥 ID 5072e1f5: NOKEY 错误&#xff1a;依赖检测失败&#xff1a;net-tools 被 mysql-community-server-8.0.26-1.el7.x86_64 …

「iOS」————APP启动优化

iOS学习APP的启动流程启动流程缺页错误主要阶段pre-main阶段main阶段启动优化pre-mainmain阶段启动优化总结流程总结APP的启动流程 启动 首先我们来了解启动的概念&#xff1a; 广义上的启动是点击图标到首页数据加载完毕狭义上的启动是点击图标到启动图完全消失的第一帧 启…

知名车企门户漏洞或致攻击者远程解锁汽车并窃取数据

漏洞概况一家大型汽车制造商的在线系统存在安全漏洞&#xff0c;可能导致客户数据泄露&#xff0c;并允许攻击者远程访问车辆。该漏洞由安全研究员Eaton Zveare发现&#xff0c;他已于2025年2月向涉事车企报告并促使漏洞修复。Zveare虽未公开车企名称&#xff0c;但透露这是在美…

Elasticsearch JS 自定义 ConnectionPool / Connection / Serializer、敏感信息脱敏与 v8 平滑迁移

0. 什么时候该用“高阶配置”&#xff1f; 复杂网络/路由需求&#xff1a;自定义“健康节点”判定、权重路由、多租户隔离。替换 HTTP 栈&#xff1a;接入企业内网网关、打通自研代理/审计、细化超时/连接细节。序列化治理&#xff1a;为超大 JSON、Bulk、查询串做定制编码/压缩…

希尔排序专栏

在排序算法的大家庭中&#xff0c;希尔排序&#xff08;Shell Sort&#xff09;以其独特的 "分组插入" 思想占据着重要地位。它是对插入排序的创造性改进&#xff0c;通过引入 "增量分组" 策略&#xff0c;大幅提升了排序效率。本文将带你深入理解希尔排序…

Android 欧盟网络安全EN18031 要求对应的基本表格填写

Android 欧盟网络安全EN18031 要求对应的基本表格填写 文章目录Android 欧盟网络安全EN18031 要求对应的基本表格填写一、背景二、18031认证预填表格三、其他1、Android EN 18031 要求对应的基本表格小结2、EN 18031的要求表格内容填写3、一定要做三方认证&#xff1f;4、欧盟网…

《Attention-driven GUI Grounding》论文精读笔记

论文链接&#xff1a;[2412.10840] Attention-driven GUI Grounding: Leveraging Pretrained Multimodal Large Language Models without Fine-Tuning 摘要 近年来&#xff0c;多模态大型语言模型&#xff08;Multimodal Large Language Models&#xff0c;MLLMs&#xff09;的…

PIDGenRc函数中lpstrRpc的由来和InitializePidVariables函数的关系

第一部分&#xff1a;./base/ntsetup/syssetup/setupp.h:404:#define MAX_PID30_RPC 5BOOL InitializePidVariables() {//// Get the Pid from HKEY_LOCAL_MACHINE\SYSTEM\Setup\Pid//Error RegOpenKeyEx( HKEY_LOCAL_MACHINE,((MiniSetup || OobeSetup) ? szFinalPidKeyNa…

Nginx学习笔记(七)——Nginx负载均衡

⚖️ Nginx学习笔记&#xff08;七&#xff09;——Nginx负载均衡 &#x1f4cc; 一、负载均衡核心概念 架构定位&#xff1a; #mermaid-svg-00aCvwmJ40DHNd66 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-00aC…

MQ积压如何处理

处理消息队列&#xff08;MQ&#xff09;积压是一个需要系统化分析的运维挑战。下面我将结合常见原因&#xff0c;分步骤说明处理方案&#xff0c;并区分应急措施和根本解决方案&#xff1a;​一、快速诊断积压原因&#xff08;核心&#xff01;&#xff09;​​​监控告警分析…