[C++ 网络协议] 套接字和地址族、数据序列
目录
1. 套接字
1.1 在Linux平台下构建套接字
1.1.1 用于接听的套接字(服务器端套接字)
1.1.2 用于发送请求的套接字(客户端套接字)
1.2 在Windows平台下构建套接字
1.2.1 Winsock的初始化
1.2.2 用于接听的套接字(服务器端套接字)
1.2.3 用于发送请求的套接字(客户端套接字)
1.3 Linux和Windows套接字的区别
1.4 套接字特性
1.4.1 socket函数
1.4.1.1 协议族信息(domain形参)
1.4.1.2 套接字类型(Type形参)
1.4.1.2.1 面向连接的套接字(SOCK_STREAM)
1.4.1.2.2 面向消息的套接字(SOCK_DGRAM)
1.4.1.3 协议的最终选择(protocol形参)
2. 地址族和数据序列
2.1 网络地址
2.1.1 IPv4(常用)
2.1.1.1 网络地址和主机地址
2.1.2 端口号
2.1.3 bind函数
2.1.3.1 sockaddr_in结构体
2.1.4 网络字节序
2.1.5 字节序转换
2.1.6 网络地址的初始化和分配
2.1.6.1 inet_addr函数
2.1.6.2 inet_aton函数(Windows不存在此函数)
2.1.6.3 inet_ntoa函数(和inet_aton函数相反)
2.1.6.4 INADDR_ANY常数
2.1.6.5 WSAStringToAddress函数(只有Windows平台有,不利于兼容性)
2.1.6.6 WSAAddressToString函数(只有Windows平台有,不利于兼容性)
2.1.6.7 服务器端初始化IP地址时非常明确,为什么还要进行IP的初始化呢?
3.其余流程函数
3.1 进入连接等待状态(listen函数)
3.2 受理客户端连接请求(accpet函数)
3.3 客户端请求连接(connect函数)
4. 基于TCP的服务器端/客户端函数调用关系
网络编程:编写程序使两台连网的计算机进行数据交换。
1. 套接字
操作系统提供名为套接字的部件,套接字是网络数据传输用的软件设备,它能够连接到因特网上,与远程计算机进行数据传输。
1.1 在Linux平台下构建套接字
对于Linux而言,socket操作与文件操作没有区别。如:close函数不仅可以关闭文件也可以关闭套接字。
1.1.1 用于接听的套接字(服务器端套接字)
第一步:调用socket函数创建套接字
#include<sts/socket.h>
int socket(int domain,int type,int protocol);
成功返回文件描述符,失败返回-1
第二步:调用bind函数分配IP地址和端口号
#include<sts/socket.h>
int bind(int sockfd,struct sockaddr* myaddr,socklen_t addrlen);
成功返回0,失败返回-1
第三步:调用listen函数转为可接收请求状态
#include<sts/socket.h>
int listen(int sockfd,int backlog);
成功返回0,失败返回-1
第四步:调用accept函数受理连接请求
#include<sts/socket.h>
int accept(int sockfd,struct sockaddr* addr,socklen_t* addrlen);
成功返回文件描述符,失败返回-1
accpet函数一直等待,直到有连接请求时,才会有返回值。
第五步:调用write函数发送数据
#include<unistd.h>ssize_t write(int fd,const void* buf,size_t nbytes);
成功则返回写入的字节数,失败返回-1
fd:文件描述符参数
buf:保存要传输数据的缓冲地址值
nbytes:要传输数据的字节数
第六步:关闭套接字
#include<unistd.h>int close(int fd);
成功返回0,失败返回-1
fd:文件描述符参数。
close函数不仅可以关闭文件也可以关闭套接字。 客户端调用close会向服务端的客户端套接字文件描述符传递EOF。
1.1.2 用于发送请求的套接字(客户端套接字)
第一步:调用socket函数创建套接字
如上。
第二步:调用connect函数连接服务器端
#include<sts/socket.h>
int connect(int sockfd,struct sockaddr* serv_addr,socklen_t addrlen);
成功返回0,失败返回-1
第三步:调用read函数读取服务器传输的信息
#include<unistd.h>ssize_t read(int fd,void *buf,size_t nbytes);
成功则返回接收的字节数(但遇到文件结尾则返回0),失败返回-1
fd:数据接收对象的文件描述符参数
buf:保存接收数据的缓冲地址值
nbytes:要接收数据的字节数
第四步:关闭套接字
如上。
1.2 在Windows平台下构建套接字
在Windows平台下构建套接字要先进行Winsock的初始化。
1.2.1 Winsock的初始化
初始化版本库
#include<winsock2.h>int WSAStartup(WORD wVersionRequested,LPWSADATA lpWSAData);
成功返回0,失败返回非0的错误代码值
wVersionRequested:WORD是通过typedef定义的unsigned short类型,这个参数是提供套接字版本信息。可借助MAKEWORD宏函数来构建版本信息,如:
MAKEWORD(1,2); //主版本为1,副版本为2,返回0x0201
MAKEWORD(2,2); //主版本为2,副版本为2,返回0x0202
lpWSAData:传入WSADATA型结构体变量地址(LPWSADATA是WSADATA的指针类型),调用完函数后会将相关参数,填充到这个参数里。
WSADATA wsaData;
if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0)
{......
}
注销版本库
#include<winsock2.h>int WSACleanup(void);
成功返回0,失败返回SOCKET_ERROR
销毁Winsock相关库,无法再调用Winsock相关函数。
1.2.2 用于接听的套接字(服务器端套接字)
第一步:调用socket函数创建套接字
#include <winsock2.h>
SOCKET socket(int af,int type,int protocol);
成功返回套接字句柄,失败返回INVALID_SOCKET
第二步:调用bind函数分配IP地址和端口号
#include <winsock2.h>
int bind(SOCKET s,const struct sockaddr* name,int namelen);
成功返回0,失败返回SOCKET_ERROR
第三步:调用listen函数转为可接收请求状态
#include <winsock2.h>
int listen(SOCKET s,int backlog);
成功返回0,失败返回SOCKET_ERROR
第四步:调用accept函数受理连接请求
#include <winsock2.h>
SOCKET accept(SOCKET s,struct sockaddr* addr,int* addrlen);
成功返回文件描述符,失败返回INVALID_SOCKET
accpet函数一直等待,直到有连接请求时,才会有返回值。
第五步:调用send函数发送数据
#include<winsock2.h>
int send(SOCKET s,const char* buf,int len,int flags);
成功返回传输字节数,失败返回SOCKET_ERROR
s:表示数据传输对象连接的套接字句柄值
buf: 保存待传输数据的缓冲地址值
len:要传输的字节数
flags:传输数据时用到的多种选项信息
第六步:关闭套接字
#include <winsock2.h>
int closeconnect(SOCKET s);
成功返回0,失败返回SOCKET_ERROR
1.2.3 用于发送请求的套接字(客户端套接字)
第一步:调用socket函数创建套接字
如上。
第二步:调用connect函数连接服务器端
#include <winsock2.h>
int connect(SOCKET s,const struct sockaddr* name,int namelen);
成功返回0,失败返回SOCKET_ERROR
第三步:调用recv函数,接收服务器端传来的数据
#include <winsock2.h>
int recv(SOCKET s,const char* buf,int len,int flags);
成功返回接收的字节数(收到EOF时为0),失败返回SOCKET_ERROR
s:表示数据接收对象连接的套接字句柄值
buf: 保存接收数据的缓冲地址值
len:要接收的最大字节数
flags:接收数据时用到的多种选项信息
第四步:关闭套接字
如上。
1.3 Linux和Windows套接字的区别
-
文件描述符和句柄的区别:
在Linux中,文件描述符是不区分文件和套接字的,即两个都是一样的
在Windows中,句柄是区分文件和套接字的,并不完全一样。
比较两个系统的socket、listen和accept函数,可以发现,其实Linux的int sockfd就对应于Windows的SOCKET s,即SOCKET这个类型,就存有套接字句柄整形值,也类似于一种编号。
-
write和send的区别:
在Linux中,有write也有send函数,来传输数据。
在windows中,send函数只是比Linux中的write函数多了最后的flag参数。
1.4 套接字特性
1.4.1 socket函数
int socket(
int domain, //套接字中使用的协议族(Protocol Family)信息
int type, //套接字数据传输类型信息
int protocol //计算机间通信中使用的协议信息
);
成功返回文件描述符,失败返回-1
一个socket套接字=协议族+套接字类型+最终协议。
1.4.1.1 协议族信息(domain形参)
协议族:套接字通信中协议的分类。
名称 | 协议族 |
PF_INET(常用) | IPv4互联网协议族 |
PF_INET6 | IPv6互联网协议族 |
PF_LOCAL | 本地通信的UNIX协议族 |
PF_PACKET | 底层套接字的协议族 |
PF_IPX | IPX Novell协议族 |
1.4.1.2 套接字类型(Type形参)
套接字类型:套接字的数据传输方式。
1.4.1.2.1 面向连接的套接字(SOCK_STREAM)
特点:
- 传输过程中数据不会丢失
- 按序传输数据
- 传输的数据不存在数据边界
- 套接字连接必须一一对应(一个客户端套接字对应服务器端的一个套接字,n个对应n个套接字)
总结:可靠的、按序传递的、基于字节的面向连接的数据传输方式的套接字。注意接收和发送数据大小要相等。
特点:传输过程中数据不会丢失、传输的数据不存在数据边界,解释:
在接收的套接字内部,有一个由字节数组组成的缓冲区,从传输端传过来的数据会先存储到这个缓冲区里,如果缓冲区满了,那么传输端就会停止传输,等待缓冲区中的数据被读取完,再继续传输。其中传输出错,也会进行重传服务,除特殊情况外,不会有数据丢失。
1.4.1.2.2 面向消息的套接字(SOCK_DGRAM)
特点:
- 快速传输
- 传输的数据可能丢失、损毁
- 传输的数据有数据边界
- 限制每次传输的大小
总结:不可靠的,不按序传递的、以数据的高速传输为目的的套接字,不存在连接的概念。注意接收和发送数据次数要相等。
特点:传输的数据具有数据边界,解释:
每次传输都有大小限制,如果超过了这个限制,那么就得分批发送,即意味着接收数据的次数应和传输次数相同。而面向连接的套接字,没有这个要求。
1.4.1.3 协议的最终选择(protocol形参)
第三个参数的意义:同一协议族中存在多个数据传输方式相同的协议。
与套接字类型对应的:
- 面向连接的套接字:TCP套接字(IPPROTO_TCP),注意接收和发送数据大小要相等。
- 面向消息的套接字:UDP套接字(IPPROTO_UDP),注意接收和发送数据次数要相等。
2. 地址族和数据序列
IP(Internet Protocol网络协议):为收发网络数据而分配给计算机的值。
端口号:区分程序中创建的套接字而分配给套接字的序号。
2.1 网络地址
分为两类:IPv4(4字节地址族)、IPv6(16字节地址族)。
2.1.1 IPv4(常用)
IPv4标准的4字节IP地址,由网络地址和主机地址组成。
2.1.1.1 网络地址和主机地址
IPv4分为如下A、B、C、D四种类型:
通过首字节可以判断其属于哪种类型:
首字节范围 | 类型 |
0~127 | A |
128~191 | B |
192~223 | C |
向对应IP地址主机传输数据,是先通过网络地址,查找到对应的路由器或交换机,再由路由器或交换机,根据主机ID将数据分发到主机上。如图:将数据发送到203.211.172.103上,会先找到网络地址为203.211.172的路由器,路由器再通过主机ID:103将数据传输给对应主机。
2.1.2 端口号
端口号由16位构成,可分配端口号范围为0~65535,但0~1023是知名端口号,会分配给特定应用程序,所以应当分配此范围之外的值。另外,虽然端口号不能重复,但TCP套接字和UDP套接字不会共用端口号,所以允许重复。例如:某TCP套接字用了9130端口,则其余TCP套接字不能使用此端口,但UDP套接字可以使用9130端口。
2.1.3 bind函数
#include<sts/socket.h>
int bind(int sockfd,struct sockaddr* myaddr,socklen_t addrlen);
成功返回0,失败返回-1
2.1.3.1 sockaddr_in结构体
sockaddr_in:保存IPv4地址信息的结构体。
struct sockaddr_in
{sa_family_t sin_family; //地址族uint16_t sin_port; //16位TCP/UDP端口号struct in_addr sin_addr; //32位IP地址char sin_zero[8]; //不使用
}struct in_addr
{in_addr_t s_addr; //32位IPv4地址
}struct sockaddr
{sa_family_t sin_family; //地址族char sa_data[14]; //地址信息
}
数据类型是POSIX(可移植操作系统接口),POSIX是为UNIX系列操作系统设立的标准。
1.sin_family成员
2.sin_port成员
保存16位端口号,是以网络字节序保存的。
3.sin_addr成员
保存32位IP地址信息,也是以网络字节序保存的。
4.sin_zero成员
无特殊含义。只是为了使结构体sockaddr_in和sockaddr结构体大小保持一致插入的成员。
为什么我们平常的使用,要先填充 sockaddr_in结构体,再转换为sockaddr结构体,而不直接填充sockaddr结构体呢?
答:因为sockaddr结构体中sa_data[14]数据的填充很麻烦,其中需包含IP地址和端口号,并且其余部分都要填充为0,才能使用。不如直接使用sockaddr_in结构体,再进行转换。填充复杂的原因是sockaddr结构体并不仅仅为IPv4而设计。
2.1.4 网络字节序
不同CPU中,向内存保存数据的方式有两种,一种是正序,直接保存,一种是倒序保存,这意味着,CPU解析数据的方式也分为两种:
- 大端序:高位字节存放到低位地址
- 小端序:高位字节存放到高位地址
所以,在数据传输时,必须统一方式,这种方式就称为网络字节序,即统一为大端序。即先把数据统一转化为大端序的格式,再进行网络传输,所以在填充sin_addr成员和sin_port成员时需要以网络字节序保存。
2.1.5 字节序转换
主机字节序和网络字节序的相互转换,被称为字节序转换。有以下函数进行转换:
unsigned short htons(unsigned short); //把short类型数据从主机字节序转换为网络字节序
unsigned short ntohs(unsigned short); //把short类型数据从网络字节序转换为主机字节序
unsigned long htonl(unsigned long); //把long类型数据从主机字节序转换为网络字节序
unsigned long ntohl(unsigned long); //把long类型数据从网络字节序转换为主机字节序
htons中的h表示主机(host)字节序。
htons中的n表示网络(network)字节序。
htons中的s指的是short(short占2个字节,所以常用于端口号的转换)。
htonl中的l值得是long(Linux中long类型占4个字节,所以常用于IP地址的转换)。
2.1.6 网络地址的初始化和分配
2.1.6.1 inet_addr函数
#include <arpa/inet.h>
in_addr_t inet_addr(const char *string);
成功则返回32位大端序整数型值,失败则返回INADDR_NONE
这个函数帮助我们将字符串形式的IP地址转换为32位整数型数据,同时也会进行网络字节序转换。 同时它也会检测无效的IP地址。
2.1.6.2 inet_aton函数(Windows不存在此函数)
inet_aton函数和inet_addr函数功能上相同。
#include <arpa/inet.h>
int inet_aton(const char *string,struct in_addr* addr);
成功则返回1,失败则返回0
string:含有需转换的IP地址信息的字符串地址值。
addr:将保存转换结果的in_addr结构体变量的地址值。
2.1.6.3 inet_ntoa函数(和inet_aton函数相反)
#include <arpa/inet.h>
char* inet_ntoa(struct in_addr* addr);
成功则返回转换的字符串地址值,失败则返回-1
将网络字节序32位整数型IP地址转换为字符串形式。
注意:在使用此函数时,返回的结果是一个指针,指向字符串信息的地址,当第二次使用这个函数时,这个地址存有的字符串信息会被覆盖掉,所以在使用时,需要立即拷贝保存地址存有的字符串信息。
2.1.6.4 INADDR_ANY常数
struct sockaddr_in addr;
memset(&addr,0,sizeof(addr));
...
addr.sin_addr.s_addr=htonl(INADDR_ANY);
INADDR_ANY常数:采用这种方式,会自动获取运行服务器端的计算机的IP地址,不必亲自输入,并且,若同一计算机中分配有多个IP地址(路由器这种),则只要端口号一致,就可以从不同IP地址里接收数据。所以服务器端优先考虑这种方式。
2.1.6.5 WSAStringToAddress函数(只有Windows平台有,不利于兼容性)
各种类型都是针对默认类型的typedef声明。
#include <winsock2.h>
INT WSAStringToAddress
(LPTSTR AddressString,INT AddressFamily,LPWSAPROTOCOL_INFO lpProtocolInfo,LPSOCKADDR lpAddress,LPINT lpAddressLength
);
成功返回0,失败返回SOCKET_ERROR
AddressString:含有IP地址和端口号的字符串地址值
AddressFamily:第一个参数中地址所属的地址族信息
lpProtocolInfo:设置协议提供者(Provider),默认为NULL
lpAddress:保存地址信息的结构体变量地址值
lpAddressLength:第四个参数中传递的结构体长度所在的变量地址值。
2.1.6.6 WSAAddressToString函数(只有Windows平台有,不利于兼容性)
各种类型都是针对默认类型的typedef声明。
#include <winsock2.h>
INT WSAAddressToString
(LPSOCKADDR lpsaAddress,DWORD dwAddressLength,LPWSAPROTOCOL_INFO lpProtocolInfo,LPTSTR lpszAddressString,LPDWORD lpdwAddressStringLength
);
成功返回0,失败返回SOCKET_ERROR
lpsaAddress:需要转换的地址信息结构体变量地址值
dwAddressLength:第一个参数中结构体的长度
lpProtocolInfo:设置协议提供者(Provider),默认为NULL
lpszAddressString:保存转换结果的字符串地址值
lpdwAddressStringLength:第四个参数中存有地址信息的字符串长度
2.1.6.7 服务器端初始化IP地址时非常明确,为什么还要进行IP的初始化呢?
因为:同一个计算机可能分配有多个IP地址,实际IP地址和计算机安装的NIC数量相等。所以服务器需要决定应接收哪个IP地址传来的数据,所以要服务器端要初始化IP地址。
3.其余流程函数
3.1 进入连接等待状态(listen函数)
当调用了listen函数,服务器端会阻塞,等待连接请求状态。意味着,只有在此之后客户端才能调用connect函数。
#include<sts/socket.h>
int listen(
int sockfd, //希望进入等待连接请求状态的套接字文件描述符,传递的描述符套接字参数为服务器端套接字
int backlog //连接请求等待队列的长度。
);
成功返回0,失败返回-1
如图:
客户端连接请求本身也是从网络中接收到的一种数据,而接收数据就需要套接字,所以第一个参数服务器端套接字,就是充当门卫,可回复客户端请求,传输"请求已收到"的信号数据。第二个参数就是可以规定,连接请求等候的队列的大小,一般与服务器端特性有关,像频繁请求的web端则至少要15。
3.2 受理客户端连接请求(accpet函数)
#include<sys/socket.h>
int accpet(
int sock, //服务器套接字的文件描述符
struct sockaddr* addr, //保存发起连接请求的客户端地址信息的变量地址值
socklen_t* addrlen //第二个参数的结构体长度。
);
成功则返回套接字文件描述符,失败则返回-1
accpet函数,受理连接请求等待队列中,待处理的客户端连接请求。函数调用成功,accept函数内部会产生用于数据I/O的套接字,并返回其文件描述符。这个套接字是自动创建的,并自动与发起连接请求的客户端建立连接。
3.3 客户端请求连接(connect函数)
#include<sys/socket.h>
int connect(
int sock, //客户端套接字文件描述符
struct sockaddr* servaddr, //保存目标服务器端地址信息的变量地址值
socklen_t addrlen //第二个参数的变量长度
);
成功返回0,失败返回-1
connect函数只有以下情况之一才会返回:
- 服务器端接收连接请求,所谓的“连接请求”,并不意味着服务器端调用accpet函数,而是服务器端把连接请求信息记录到等待队列中。所以connect函数返回后并不立即进行数据交换。
- 发生断网等异常情况而中断连接请求
4. 基于TCP的服务器端/客户端函数调用关系
图中的总体流程整理如下:服务器端创建套接字后连续调用bind、listen函数进入等待状态,客户端通过调用connect函数发起连接请求。需要注意的是,客户端只能等到服务器端调用listen函数后才能调connect函数。同时要清楚,客户端调用connect函数前,服务器端有可能率先调用accept函数。当然,此时服务器端在调用accept函数时进入阻塞( blocking)状态,直到客户端调connect函数为止。
相关文章:

[C++ 网络协议] 套接字和地址族、数据序列
目录 1. 套接字 1.1 在Linux平台下构建套接字 1.1.1 用于接听的套接字(服务器端套接字) 1.1.2 用于发送请求的套接字(客户端套接字) 1.2 在Windows平台下构建套接字 1.2.1 Winsock的初始化 1.2.2 用于接听的套接字(服务器端套接字) 1.2.3 用于发送请求的套接字(客户端套…...

AI 绘画Stable Diffusion 研究(八)sd采样方法详解
大家好,我是风雨无阻。 本文适合人群: 希望了解stable Diffusion WebUI中提供的Sampler究竟有什么不同,想知道如何选用合适采样器以进一步提高出图质量的朋友。 想要进一步了解AI绘图基本原理的朋友。 对stable diffusion AI绘图感兴趣的朋…...
线程池满了如何处理
某天搬砖时遇到一个问题,我创建了一个线程池执行任务,刚开始的时候还是一切,结果第二天发现有些任务没有正常执行。一看日志才发现是高峰期时线程池给我占用慢了,任务被丢掉了。 举个例子,我创建了一个线程池&#…...

Java多线程编程中的线程间通信
Java多线程编程中的线程间通信 基本概念: 线程间通信是多线程编程中的一个重要概念,指的是不同线程之间如何协调和交换信息,以达到共同完成任务的目的。 线程间通信的目的 是确保多个线程能够按照一定的顺序和规则进行协作ÿ…...
write javaBean error, fastjson version 1.2.76
fastjson JSON.toJSONString 报错: > [0] JavaBeanSerializer.java->541: com.alibaba.fastjson.serializer.JavaBeanSerializer->write()> [1] JavaBeanSerializer.java->154: com.alibaba.fastjson.serializer.JavaBeanSerializer->write()>…...

Tomcat的部署及优化(多实例和动静分离)
目录 绪论 1、tomact 1.1 核心组件 1.2 什么是 servlet 1.3 什么是 JSP? 1.4 Tomcat 功能组件结构 1.5 Tomcat 请求过程 2、Tomcat 服务部署 2.1 tomcat自身优化: 2.2 内核优化 2.3 jvm 2.3.1 jvm配置 2.3.2 Tomcat配置JVM参数 2.3.3 jvm优化 3、tom…...

品牌推广革新之道:海外网红与内容营销的融合
随着数字时代的来临,品牌推广的方式正在经历着革命性的变化。传统的广告手段逐渐失去了吸引力,而内容营销正成为品牌推广的新宠儿。尤其是海外网红的崛起,不仅改变了推广方式,更重新定义了品牌与消费者之间的互动关系。本文Nox聚星…...

【 BERTopic应用 02/3】 分析卡塔尔世界杯推特数据
摄影:Fauzan Saari on Unsplash 一、说明 这是我们对世界杯推特数据分析的第3部分,我们放弃了。我们将对我们的数据进行情绪分析,以了解人们对卡塔尔世界杯的感受。我将在这里介绍的一个功能强大的工具包是Hugging Face,您可以在…...
TypeScript教程(三)变量声明
一、变量声明 变量是一种使用方便的占位符,用于引用计算机内存地址,可以将变量看做存储数据的容器 命名规则: 1.变量名称可以包含数字和字母 2.除了下划线_和美元$符号外,不能包含其他特殊字符,包括空格 3.变量名…...

【数据结构】堆的实现,堆排序以及TOP-K问题
目录 1.堆的概念及结构 2.堆的实现 2.1初始化堆 2.2销毁堆 2.3取堆顶元素 2.4返回堆的大小 2.5判断是否为空 2.6打印堆 2.7插入元素 2.8堆的向上调整 2.9弹出元素 2.10堆的向下调整 3. 建堆时间复杂度 4. 堆的应用 4.1 堆排序 4.2 TOP-K问题 1.堆的概念及结构 …...

释放马氏距离的力量:用 Python 探索多元数据分析
一、说明 马哈拉诺比斯距离(Mahalanobis Distance)是一种测量两个概率分布之间距离的方法。它是基于样本协方差矩阵的函数,用于评估两个向量之间的相似程度。Mahalanobis Distance考虑了数据集中各个特征之间的协方差,因此比欧氏距…...

【不限于联想Y9000P电脑关盖再打开时黑屏的解决办法】
不限于联想Y9000P电脑关盖再打开时黑屏的解决办法 问题的前言问题的出现问题拟解决 问题的前言 事情发生在昨天,更新了Win11系统后: 最惹人注目的三处地方就是: 1.可以查看时间的秒数了; 2.右键展示的内容变窄了; 3.按…...

策略模式实战应用
场景 假设做了个卖课网站,会员等级分为月vip、年vip、终生vip,每个等级买课的优惠力度不一样,传统的写法肯定是一堆的 if-else,现在使用策略模式写出代码实现 代码实现 策略模式的核心思想就是对扩展开放,对修改关闭…...
JAVA集合-Map
// 【Map】:双列集合,键值对形式存储,映射关系(kay,value) // 实现:HashMap // 子接口:SortedMap Map的子接口 // 实现类:TreeMap // HashMap // 1。可以插入null // …...

利用Simulink Test进行模型单元测试 - 1
1.搭建用于测试的简单模型 随手搭建了一个demo模型MilTestModel,模型中不带参数 2.创建测试框架 1.模型空白处右击 测试框架 > 为‘MilTestModel’创建 菜单 2.在创建测试框架对话框中,点击OK,对应的测试框架MilTestMode_Harness1就自动…...
深入探讨代理技术:保障网络安全与高效爬虫
1. Socks5代理与IP代理的区别与应用 Socks5代理和IP代理是代理技术中的两个重要方面,它们有着不同的特点和应用场景。Socks5代理是一种协议,支持TCP和UDP流量传输,适用于需要实时数据传输的场景,例如在线游戏或实时通信应用。而I…...

HDMI接口的PCB布局布线要求
高清多媒体接口(High Definition Multimedia Interface),简称:HDMI,是一种全数字化视频和声音发送接口,可以发送未压缩的音频及视频信号。随着技术的不断提升,HDMI的传输速率也不断的提升&#…...
Linux tar包安装 Prometheus 和 Grafana(知识点:systemd Unit/重定向)
0. 介绍 用tar包的方式安装 Prometheus 和 Grafana Prometheus:开源的监控方案Grafana:将Prometheus的数据可视化平台 Prometheus已经有了查询功能为什么还需要grafana呢?Prometheus基于promQL这一SQL方言,有一定门槛!Grafana基于浏览器的操作与可视化图表大大降低了理解难…...

【Vue框架】用户和请求
前言 在上一篇 【Vue框架】Vuex状态管理 针对Vuex状态管理以getters.js进行说明,没有对其中state引入的对象进行详细介绍,因为整体都比较简单,也就不对全部做详细介绍了;但其中的user.js涉及到获取用户的信息、前后端请求的token…...

NGINX组件(rewrite)
一、location匹配的规则和优先级(*) URI:统一资源标识符,是一种字符串标识,用于标识抽象的或者是物理资源;如:文件、图片、视频等 nginx中的URI匹配的是:网址”/“后的路径 如&…...

华为云AI开发平台ModelArts
华为云ModelArts:重塑AI开发流程的“智能引擎”与“创新加速器”! 在人工智能浪潮席卷全球的2025年,企业拥抱AI的意愿空前高涨,但技术门槛高、流程复杂、资源投入巨大的现实,却让许多创新构想止步于实验室。数据科学家…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...
多场景 OkHttpClient 管理器 - Android 网络通信解决方案
下面是一个完整的 Android 实现,展示如何创建和管理多个 OkHttpClient 实例,分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)
CSI-2 协议详细解析 (一) 1. CSI-2层定义(CSI-2 Layer Definitions) 分层结构 :CSI-2协议分为6层: 物理层(PHY Layer) : 定义电气特性、时钟机制和传输介质(导线&#…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...

SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...

初学 pytest 记录
安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面: 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...