Linux应用开发之网络套接字编程
套接字(Socket)是计算机网络数据通信的基本概念和编程接口,允许不同主机上的进程(运行中的程序)通过网络进行数据交换。它为应用层软件提供了发送和接收数据的能力,使得开发者可以在不用深入了解底层网络细节的情况下进行网络编程,屏蔽了应用程序对底层协议的操作,使得应用程序使用网络进行数据传输变得更简便,使代码更容易维护。socket英文直译为“插座”,可以理解为应用层调用网络服务的接口。
套接字主要由以下三个属性组成:
网络地址:通常是IP地址,用于标识网络上的设备。
端口号:用于标识设备上的特定应用或进程。端口号是一个16位的数字,范围从0到65535。
协议:如TCP(传输控制协议)或UDP(用户数据报协议),定义了数据传输的规则和格式。
根据数据传输方式的不同,主要有两种类型的套接字:
流套接字(Stream Sockets):基于TCP协议,提供面向连接、可靠的数据传输服务。数据像流水一样连续传输,接收方按发送顺序接收数据,适用于需要准确无误传输数据的应用,如网页服务器。
数据报套接字(Datagram Sockets):基于UDP协议,提供无连接的数据传输服务。每个报文段独立传输,可能会丢失或无法保证顺序,适用于对传输速度要求高但可以容忍一定丢包率的应用,如在线视频会议。
套接字通过封装TCP/IP协议细节,提供了一组API,允许应用程序创建套接字、绑定地址和端口、监听连接、接受连接、发送和接收数据等。在网络通信中,通常一个套接字负责监听和接受外部连接(服务器套接字),另一个套接字负责发起连接(客户端套接字)。
套接字的引入极大地简化了网络编程的复杂度,使得开发者可以专注于应用逻辑的实现,而无需深入了解网络协议栈的内部工作原理。通过使用套接字,可以轻松实现不同计算机之间的数据交换,支持构建分布式系统和多种网络应用。
网络字节序和主机字节序
在网络编程中,特别是在跨平台和网络通信时,字节序(Byte Order)是非常重要的概念。字节序指的是多字节数据在内存中的存储顺序。主要有两种字节序:
大端字节序(Big-Endian):高位字节存储在内存的低地址处,低位字节存储在高地址处。这种字节序遵循自然数字的书写习惯,也被称为网络字节序(Network Byte Order)或网络标准字节序,因为它在网络通信中被广泛采用,如IP协议就要求使用大端字节序。
小端字节序(Little-Endian):低位字节存储在内存的低地址处,高位字节存储在高地址处。这是Intel x86-64架构以及其他一些现代处理器普遍采用的字节序,称为主机字节序(Host Byte Order)。
在网络通信中,为了让不同字节序的主机能够相互理解对方的数据,常常需要进行字节序转换。例如,发送数据前需要将主机字节序转换为网络字节序,接收数据后则需要将网络字节序转换为主机字节序。例如,如果你有一个IP地址或端口号(通常存储为整数)需要在网络上传输,就需要先使用htons()或htonl()将其转换为网络字节序,然后在网络另一端接收时,使用ntohs()或ntohl()将其转换回主机字节序。这样可以确保数据在网络中的传输不受不同主机字节序的影响。
htol函数
作用是将无符号整数 hostlong 从主机字节顺序(h)转换为网络字节顺序(n),一般用于ip地址的转换。
函数原型为uint32_t htonl(uint32_t hostlong);
htos函数
作用是将无符号短整数 hostshort 从主机字节顺序(h)转换为网络字节顺序(n)。一般用于端口号的转换。
函数原型为uint16_t htons(uint16_t hostshort);
ntohl函数
作用是将无符号整数 netlong 从网络字节顺序(n)转换为主机字节顺序(h)。
函数原型为uint32_t ntohl(uint32_t netlong);
ntohs函数
作用是将无符号短整数 netshort 从网络字节顺序(n)转换为主机字节顺序(h)。
函数原型为uint16_t ntohs(uint16_t netshort);
用于将ip地址转换为网络字节序的函数推荐以下几种
inet_aton函数
函数原型为int inet_aton(const char *cp, struct in_addr *inp);
作用是将来自 IPv4 点分十进制表示法的 Internet 主机地址 cp 转换为二进制形式(以网络字节顺序)并将其存储在 inp 指向的结构体中。
return int 成功返回 1;失败 返回 0
inet_pton函数
函数原型为int inet_pton(int af, const char *src, void *dst);
作用是字符串格式转换为sockaddr_in格式
int af: 通常为 AF_INET 用于IPv4地址,或 AF_INET6 用于IPv6地址
char *src: 包含IP地址字符串的字符数组,如果是IPv4地址,格式为点分十进制(如 "192.168.1.1");如果是IPv6地址,格式为冒号分隔的十六进制表示(如 "2001:0db8:85a3:0000:0000:8a2e:0370:7334")
void *dst:指向一个足够大的缓冲区(对于IPv4是一个struct in_addr结构体,对于IPv6是一个struct in6_addr结构体),用于存储转换后的二进制IP地址
return int : 成功转换返回0; 输入地址错误返回1;发生错误返回-1
inet_ntoa函数
函数原型为char *inet_ntoa(struct in_addr in);
作用是将主机字节序存储的ip地址转换为字符型
in 将以网络字节顺序给出的 Internet 主机地址 in 转换为 IPv4 点分十进制表示法的字符串。字符串存储在静态分配的缓冲区中,后续调用将覆盖该缓冲区。
return char* 缓冲区指针
TCP协议开发常用函数
socket函数
函数原型为int socket(int domain, int type, int protocol);
作用是在通信域中创建一个未绑定的socket,并返回一个文件描述符,该描述符可以在后续对socket进行操作的函数调用中使用
domain用于指定要创建套接字的通信域。一般使用以下三种。
AF_UNIX:本地通信,通常用于 UNIX 系统间的进程间通信。
AF_INET:IPv4 互联网协议。
AF_INET6:IPv6 互联网协议。
type 用于指定要创建的socket类型,一般使用以下两种
SOCK_STREAM:提供序列化、可靠的、双向的、基于连接的字节流。可以支持带外数据传输机制。
SOCK_DGRAM:支持数据报(无连接、不可靠的固定最大长度的消息)。
使用TCP协议就选第一个,UDP协议选第二个
这个参数还可以和以下两种配合使用,可以同时设置
SOCK_NONBLOCK:在新文件描述符引用的打开文件描述符上设置 O_NONBLOCK 文件状态标志(参见 open(2))。使用此标志可以节省调用 fcntl(2) 来实现相同结果的额外调用。
SOCK_CLOEXEC:在新文件描述符上设置关闭时执行(FD_CLOEXEC)标志。
protocol 指定要与socket一起使用的特定协议。指定协议为 0 会导致 socket() 使用适用于所请求的socket类型的未指定的默认协议,一般设置为0即可,
成功创建则返回文件描述符,失败返回-1
bind函数
函数原型为int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
作用是当使用 socket创建套接字时,它存在于一个名称空间(地址族)中,但没有为其分配地址。bind() 将由 addr 指定的地址(ip地址和端口号)分配给文件描述符 sockfd 所引用的套接字。addrlen 指定了 addr 指向的地址结构的大小(以字节为单位)。传统上,这个操作被称为“给套接字分配一个名称”
ockfd 套接字文件描述符
addr 指定的地址。地址的长度和格式取决于socket的地址族
addrlen addr 指向的地址结构的大小(以字节为单位)。填sizeof获取struct sockaddr类型变量的大小
return int 成功 0 失败 -1
地址族的概念
在网络编程中,地址族(Address Family)指定了套接字(socket)使用的网络协议类型以及地址的格式。简而言之,地址族决定了网络通信的范围和方式,比如是在同一台机器上的进程间通信,还是在网络上不同主机间的通信。每种地址族都支持特定类型的通信协议和地址格式。下面是一些常见的地址族:
① AF_INET
代表IPv4网络协议的地址族,使用32位地址。
主要用于互联网上的通信。
地址格式通常为点分十进制,如192.168.1.1。
② AF_INET6
代表IPv6网络协议的地址族,使用128位地址。
是IPv4的后继,旨在解决IPv4地址耗尽问题,并提供更多的功能。
地址格式为冒号分隔的十六进制,如2001:0db8:85a3:0000:0000:8a2e:0370:7334。
③ AF_UNIX (或 AF_LOCAL)
用于同一台机器上的进程间通信(IPC)。
使用文件系统路径名作为地址。
这种方式不通过网络层进行数据传输,而是在操作系统内部完成,因此效率较高。
上述函数都使用了struct sockaddr结构体,他存储了地址族和ip地址,端口等信息,声明如下
struct sockaddr {
sa_family_t sa_family; // 地址家族,如 AF_INET、AF_INET6、AF_UNIX 等
char sa_data[14]; // 用于存储具体地址数据的数组,其布局取决于地址
}
如果我们使用常见的IPV4,IPV6,这样将ip地址,端口号一起放在一个char数组中,很难对其进行读取或者赋值,所以对于IPV4协议,在设置时使用struct sockaddr_in结构体结合pton函数直接转换为网络字节序更加方便,在调用函数时直接强转为struct sockaddr型即可
struct sockaddr_in {
sa_family_t sin_family; /* 地址族:AF_INET */
in_port_t sin_port; /* 端口号,网络字节顺序 */
struct in_addr sin_addr; /* 互联网地址 */
};
sin_family 总是设置为 AF_INET。
sin_port 包含端口号,以网络字节顺序表示。低于 1024 的端口号称为特权端口(或有时称为:保留端口)。只有特权进程(在 Linux 中:具有 CAP_NET_BIND_SERVICE 用户命名空间中的权限,控制其网络命名空间)可以绑定到这些套接字。
例如
struct sockaddr_in server_addr
inet_pton(AF_INET,"0.0.0.0",&server_addr.sin_addr); //本机ip地址可以表示为0.0.0.0
server_addr.sin_port = htons(6666);
listen函数
函数原型为int listen(int sockfd, int backlog);
作用是将 sockfd 指定的套接字标记为被动套接字,即将用于使用 accept接受传入的连接请求。由服务端调用
sockfd 监听连接请求的套接字文件描述符,也就是客户端的套接字文件描述符,要求该描述符已经通过bind函数绑定到一个本地地址。
backlog 未被及时响应的连接可以被放入队列等待连接,该参数指定等待队列可以容纳的最大连接数
return int 成功 0 失败 -1
accept函数
函数原型为int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
作用是从监听套接字 sockfd 的待处理连接队列中提取第一个连接请求,创建一个新的连接套接字,并返回指向该套接字的新文件描述符。返回的是客户端套接字的文件描述符,(是返回的可以和客户端通信的文件描述符,也可以理解为是客户端的文件描述符,可以通过此来和客户端进行通信)新创建的套接字不处于监听状态,就与之后主动连接的客户端的套接字形成了一对一的关系,原始套接字 sockfd 不受此调用的影响。如果调用之后,没有客户端来连接,就会挂起等待(阻塞),等到接收到为止。
sockfd 一个使用 socket(2) 创建、使用 bind(2) 绑定到本地地址,并在 listen(2) 后监听连接的套接字。
addr 要么是一个空指针,要么是一个指向 sockaddr 结构的指针,用于返回连接socket的地址,即客户端的ip地址和端口号信息
addrlen 如果 address 不是空指针,则为一个指向 socklen_t 对象的指针,该对象在调用前指定提供的 sockaddr 结构的长度,并在调用后指定存储地址的长度。先定义一个socklen_t 类型的变量,用sizeof接收大小,然后传入指针
return int 返回一个新的套接字文件描述符,用于与客户端通信,所以可以看做是客户端的文件描述符,如果失败返回-1,并设置errno来表示错误原因
connect函数
函数原型为int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
由客户端调用,作用是与服务端建立连接。
sockfd 客户端套接字的文件描述符
addr 指向sockaddr结构体的指针,包含目的地地址信息
addrlen 指定addr指向的结构体的大小
return int 成功 0,失败 -1,并设置errno以指示错误原因
send函数
函数原型为ssize_t send(int sockfd, const void *buf, size_t len, int flags);
用于向另一个套接字传输消息。默认会阻塞,需要不阻塞的需要设置flags
sockfd 发送套接字的文件描述符。
buf 发送缓冲区,并非操作系统分配为服务端和客户端分配的缓冲区,而是用户为了发送数据,自己维护的字节序列。const修饰表名它是“只读”的,即send函数不会修改这块内存的内容。
len 要发送的数据的字节长度。它决定了从buf指向的缓冲区中将发送多少数据。
flags flags 对于大多数应用,这个参数被设置为0,表示不使用任何特殊行为。
MSG_DONTWAIT 启用非阻塞操作;如果操作会阻塞,则返回 EAGAIN 或 EWOULDBLOCK。这提供了类似于设置 O_NONBLOCK 标志(通过 fcntl(2) F_SETFL 操作)的行为,但不同之处在于 MSG_DONTWAIT 是一个每次调用的选项,而 O_NONBLOCK 是对打开文件描述符(参见 open(2))的设置,将影响调用进程中的所有线程以及持有引用相同打开文件描述符的其他进程。
return ssize_t成功发送的字节数。如果出现错误,它将返回-1,并设置errno以指示错误的具体原因。
recv函数
函数原型为ssize_t recv(int sockfd, void *buf, size_t len, int flags);
作用是从套接字关联的连接中接收数据。默认会阻塞,设置不阻塞需要设置flags
sockfd 套接字文件描述符。
buf 接收缓冲区,同样地,此处也并非内核维护的缓冲区。
len 缓冲区长度,即buf可以接收的最大字节数。
flags flags 参数是以下标志之一或多个的按位或。对于大多数应用,这个参数被设置为0,表示不使用任何特殊行为。
MSG_DONTWAIT 启用非阻塞操作;如果操作会阻塞,则调用失败
MSG_ERRQUEUE 此标志指定应该从套接字错误队列中接收排队的错误。
MSG_OOB 此标志请求接收在正常数据流中不会接收到的带外数据。
MSG_PEEK 此标志导致接收操作从接收队列的开头返回数据,而不从队列中删除该数据。因此,后续的接收调用将返回相同的数据。
MSG_TRUNC 对于原始(AF_PACKET)、Internet 数据报、netlink和 UNIX 数据报套接字:返回报文段或数据报的实际长度,即使它比传递的缓冲区长。
MSG_WAITALL 此标志请求操作阻塞,直到满足完整的请求。
return ssize_t 返回接收到的字节数,如果连接已经正常关闭,返回值将是0。如果出现错误,返回-1,并且errno变量将被设置为指示错误的具体原因。
shutdown函数
函数原型为int shutdown(int sockfd, int how);
作用是关闭套接字的一部分或全部连接
sockfd 套接字文件描述符
how 指定关闭的类型。其取值如下:
SHUT_RD:关闭读。之后,该套接字不再接收数据。任何当前阻塞在recv调用上的操作都将返回0。只会影响本端,不会触发挥手。从数据角度来看,套接字上接收缓冲区已有的数据将被丢弃,如果再有新的数据流到达,会对数据进行 ACK,然后悄悄地丢弃。也就是说,对端还是会接收到 ACK,在这种情况下根本不知道数据已经被丢弃了。此操作只影响本端,不会触发挥手操作
SHUT_WR:关闭写。之后,试图通过该套接字发送数据将导致错误。如果使用此选项,TCP连接将发送一个FIN包给连接的对端,表明此方向上的数据传输已经完成。此时对端的recv调用将接收到0。
关闭连接的“写”这个方向,这就是常被称为”半关闭“的连接。此时,不管套接字引用计数的值是多少,都会直接关闭连接的写方向。套接字上发送缓冲区已有的数据将被立即发送出去,并发送一个 FIN 报文给对端。应用程序如果对该套接字进行写操作会报错。
SHUT_RDWR:关闭读写。同时关闭套接字的读取和写入部分,等同于分别调用SHUT_RD和SHUT_WR。之后,该套接字既不能接收数据也不能发送数据。相当于 SHUT_RD 和 SHUT_WR 操作各一次,关闭套接字的读和写两个方向。
return int 成功 0 失败 -1,并设置errno变量以指示具体的错误原因。
close函数
函数原型为int close(int __fd);
用于关闭一个之前通过open()、socket()等函数打开的文件描述符
close会对套接字引用计数减一,一旦发现套接字引用计数到 0,就会对套接字进行彻底释放,并且会关闭 TCP 两个方向的数据流。但是close调用之后,引用计数并不一定会降到0,如果没有降到0就不会触发四次挥手。但是在当前进程内一定无法使用该套接字进行读/写。
在输入方向,系统内核会将该套接字设置为不可读,任何读操作都会返回异常。
在输出方向,系统内核尝试将发送缓冲区的数据发送给对端,并最后向对端发送一个 FIN 报文,接下来如果再对该套接字进行写操作会返回异常。
如果对端没有检测到套接字已关闭,还继续发送报文,就会收到一个 RST 报文,告诉对端:“Hi, 我已经关闭了,别再给我发数据了。
int __fd: 这是一个整数值,表示要关闭的文件描述符
return: 成功关闭文件描述符时,close()函数返回0,失败返回-1,例如试图关闭一个已经关闭的文件描述符或系统资源不足,close()会返回-1
shutdown和close函数的区别
TCP通信中,套接字也是通过文件描述符操控的,底层同样存储在struct file结构体中,socket相关的数据存在该类型结构体实例的私有数据字段,因此,我们通过close()关闭套接字,效果和关闭文件是类似的,都是使得底层文件描述的引用计数减一,若引用计数减为0则释放套接字相关的资源。
1、close 会关闭当前进程下的连接,并释放所有连接对应的资源,而 shutdown 并不会释放掉套接字和所有的资源。
2、close 存在引用计数的概念,并不一定导致该套接字不可用;shutdown 则不管引用计数,直接使得该套接字不可用,如果有别的进程企图使用该套接字,将会受到影响。
3、close 的引用计数导致不一定会发出 FIN 结束报文,而 shutdown 则总是会发出 FIN 结束报文,这在我们打算关闭连接通知对端的时候,是非常重要的
4、close 函数并不能帮助我们关闭连接的一个方向, shutdown 函数才可以。
UDP协议开发常用函数
UDP通讯也使用socket,与TCP的主要差别在于使用流程,接收和发送的函数与TCP不一样。由于UDP是无连接的传输方式,不存在握手这一步骤,所以在绑定地址之后,服务端不需要listen,客户端也不需要connect,服务端同样不需要accept,只要服务端绑定以后,就可以相互发消息了,由于没有握手过程,两端都不能确定对方是否收到消息,这也是UDP协议不如TCP协议可靠的地方。
同样的在使用UDP协议的过程时,如果使用IPV4,那么也可以使用struct sockaddr_in结构体来方便我们设置IP地址和端口号,在调用相关函数时再强转为struct sockaddr型。
recvfrom函数
函数原型为ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
作用是将接收到的消息放入缓冲区 buf 中。默认是阻塞的
sockfd 套接字文件描述符 自己的套接字
buf 缓冲区指针
len 缓冲区大小
flags 通信标签,详见recv方法说明
src_addr 可以填NULL,如果 src_addr 不是 NULL,并且底层协议提供了消息的源地址,则该源地址将被放置在 src_addr 指向的缓冲区中。从而获取数据来源的地址信息,用于之后的发送
addrlen 如果src_addr不为NULL,它应初始化为与 src_addr 关联的缓冲区的大小。返回时,addrlen 被更新为包含实际源地址的大小。如果提供的缓冲区太小,则返回的地址将被截断;在这种情况下,addrlen 将返回一个大于调用时提供的值。
return ssize_t 实际收到消息的大小。如果接收失败,返回-1
sendto函数
函数原型为ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
作用是向指定地址发送缓冲区中的数据(一般用于UDP模式)
sockfd 套接字文件描述符 也是自己的套接字
buf 缓冲区指针
len 缓冲区大小
flags 通信标签,详细见send方法说明,同样一般为0
dest_addr 目标地址。如果用于连接模式,该参数会被忽略
addrlen 目标地址长度
return ssize_t 发送的消息大小。发送失败返回-1
相关文章:
Linux应用开发之网络套接字编程
套接字(Socket)是计算机网络数据通信的基本概念和编程接口,允许不同主机上的进程(运行中的程序)通过网络进行数据交换。它为应用层软件提供了发送和接收数据的能力,使得开发者可以在不用深入了解底层网络细…...

实现RabbitMQ多节点集群搭建
目录 引言 一、环境准备 二、利用虚拟机搭建 三、镜像集群配置 四、HAProxy实现负载均衡(主用虚拟机操作) 五、测试RabbitMQ集群搭建情况 引言 在现代分布式系统中,消息队列(Message Queue)扮演着至关重要的角色,而 RabbitMQ 作为…...

GLIDE论文阅读笔记与DDPM(Diffusion model)的原理推导
Abstract 扩散模型(Diffusion model)最近被证明可以生成高质量的合成图像,尤其是当它们与某种引导技术结合使用时,可以在生成结果的多样性与保真度之间进行权衡。本文探讨了在文本条件图像生成任务中使用扩散模型,并比…...

机器学习——放回抽样
为了构建树集成模型,需要一种叫做有放回采样的技术。 以4个标记为演示,分别是红色、黄色、绿色和蓝色,用一个黑色的袋子把这四个标记的例子放进去,然后从这个袋子里有放回地抽取四次,抽出一个标记,结果是绿…...
前端内存泄漏:原理、检测与防范实践
一、什么是内存泄漏 内存泄漏(Memory Leak)是指程序中已动态分配的堆内存由于某种原因未能被释放或无法被释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。 在前端开发中,虽然现代浏览器具备垃…...

Go的隐式接口机制
正确使用Interface 不要照使用C/Java等OOP语言中接口的方式去使用interface。 Go的Interface的抽象不仅可以用于dynamic-dispatch 在工程上、它最大的作用是:隔离实现和抽象、实现完全的dependency inversion 以及interface segregation(SOLID principle中的I和D)。…...
UE音频中间件wwise插件
虚幻引擎用wwise插件有什么用? 没有这个插件不是也能播放声音吗? 为什么要用他? 在Unreal Engine(UE)中使用 Wwise 插件,不是因为 UE 不能做声音,而是因为 Wwise 更强、更专业,适合复杂的音频需求。 🎧 …...
C++.cstring string
C.cstring string 1. C 中的字符串概述1.1 C 中字符串的两种表示方式C 中的 cstring示例代码 C 中的 string示例代码 1.2 C 中字符串的使用场景使用 cstring 的场景使用 string 的场景示例对比使用 cstring 的示例使用 string 的示例 2. C 中的 cstring2.1 cstring 的定义与基本…...
Spring AOP 和 AspectJ 有什么区别
1. 织入方式 Spring AOP: 运行时织入:Spring AOP 使用动态代理技术(如 JDK 动态代理或 CGLIB 代理)在运行时创建代理对象。 依赖 Spring 容器:仅支持 Spring 管理的 Bean。 AspectJ: 编译时织入…...

报表/报告组件(二)-实例与实现解释
上篇《报表/报告组件(一)-指标/属性组件设计》介绍了组件核心指标/属性设计,本文以实例介绍各个特性的实现和效果,实例是多个报告融合,显示所有的特性。 设计 指标/属性组件是报告/报表关键部分,上篇已介绍过,本节回顾…...
linux的实时性
Linux 的实时性取决于其内核配置和使用场景。标准 Linux 内核(非实时内核)在设计上更注重吞吐量和公平调度,而非严格的实时性。但通过以下方式可以显著提升其实时性能: 1. 标准 Linux 内核的实时性 优点: 适用于大多数…...
Opencv4 c++ 自用笔记 04 图像滤波与边缘检测
图像滤波与边缘检测 直接采集到的图像可能带有噪声的干扰,因此去除噪声是图像预处理中十分重要的一步。图像滤波是图像噪声去除的重要方式。 图像卷积 卷积操作广泛应用于信号处理领域,而图像本质上可以视为一种二维信号数据。 卷积过程可以理解为一…...

流媒体基础解析:音视频封装格式与传输协议
在视频处理与传输的完整流程中,音视频封装格式和传输协议扮演着至关重要的角色。它们不仅决定了视频文件的存储方式,还影响着视频在网络上的传输效率和播放体验。今天,我们将深入探讨音视频封装格式和传输协议的相关知识。 音视频封装格式 什…...

一个html实现数据库自定义查询
使用场景 应用上线后甲方频繁的找开发查询数据库数据,且没有固定的查询规律,产品经理也没有规划报表需求。 实现方案 后端开放自定义sql查询,屏蔽所有数据库的高危操作,将常用查询的sql放在一个html中的js中直接查询࿰…...
OCC笔记:TopoDS_Edge上是否一定存在Geom_Curve
1. 问题 写occt代码时,访问边的几何数据,通常有以下代码,若边不为空,BRep_Tool::Curve函数是否能返回Curve的有效对象指针呢? //其他略...const TopoDS_Edge& curEdge TopoDS::Edge(edgeExp.Current()); if( cu…...
Python aiohttp 全面指南:异步HTTP客户端/服务器框架
边写代码零食不停口 盼盼麦香鸡味块 、卡乐比(Calbee)薯条三兄弟 独立小包、好时kisses多口味巧克力糖、老金磨方【黑金系列】黑芝麻丸 边写代码边贴面膜 事业美丽两不误 DR. YS 野森博士【AOUFSE/澳芙雪特证】377专研美白淡斑面膜组合 优惠劵 别光顾写…...
更新已打包好的 Spring Boot JAR 文件中的 class 文件
# 1. 解压原始 JAR unzip -q original-app.jar -d temp # 2. 替换 class 文件 cp ~/projects/new-classes/*.class temp/BOOT-INF/classes/com/example/ # 3. 保留原始清单 cp temp/META-INF/MANIFEST.MF . # 4. 重新打包 jar -cf0m new-app.jar MANIFEST.MF -C temp/ . # …...
容器(如 Docker)中,通常不建议运行多个进程或要求进程必须运行在前台
在容器(如Docker)中,通常不建议运行多个进程或要求进程必须运行在前台,这与容器的设计理念、资源管理和生命周期管理机制密切相关。以下是具体原因和深入解析: 一、容器的设计理念:单一职责原则 容器的核…...
conda管理环境指令综合(随时更新)
创建环境和删除环境 #创建环境 conda create --name envname#删除环境 conda env remove --name envname克隆环境 # 查看现有环境列表 conda env list# 执行克隆操作 conda create --name 新环境名称 --clone 原环境名称# 示例:将名为"tf2"的环境克隆…...
从Java的JDK源码中学设计模式之装饰器模式
装饰器模式是一种极具弹性的结构型设计模式,它允许我们通过组合的方式动态扩展对象功能而无需修改原有结构。本文将通过JDK源码中的实际应用和通俗易懂的代码示例,带你深入了解这一强大模式的精髓。 装饰器模式核心原理 装饰器模式的核心思想ÿ…...

鸿蒙电脑会在国内逐渐取代windows电脑吗?
点击上方关注 “终端研发部” 设为“星标”,和你一起掌握更多数据库知识 10年内应该不会 用Windows、MacOS操作系统的后果是你的个人信息可能会被美国FBI看到,但绝大多数人的信息FBI没兴趣去看 你用某家公司的电脑系统,那就得做好被某些人监视的下场,相信…...

持续领跑中国异地组网路由器市场,贝锐蒲公英再次登顶销量榜首
作为国产远程连接SaaS服务的创领者,贝锐持续引领行业发展,旗下贝锐蒲公英异地组网路由器,凭借出色的技术实力和市场表现,斩获2024年线上电商平台市场销量份额中国第一的佳绩,充分彰显了其在网络解决方案与异地组网领域…...

Spring AI 系列3: Promt提示词
一、Promt提示词 Promt提示是引导 AI 模型生成特定输出的输入, 提示的设计和措辞会显著影响模型的响应。 在 Spring AI 中与 AI 模型交互的最低层级,处理提示有点类似于在 Spring MVC 中管理”视图”。 这涉及创建带有动态内容占位符的大段文本。 这些占…...
Nginx 的配置文件
核心概念: 指令 (Directives): 配置文件的基本构建块。每条指令以分号 ; 结束。指令可以设置参数(如 worker_processes auto;)。 上下文 (Contexts): 指令被组织在特定的块(用花括号 {} 包围)中,称为上下文…...

Redis:安装与常用命令
🌈 个人主页:Zfox_ 🔥 系列专栏:Redis 🔥 安装 Redis 使⽤apt安装 apt install redis -y⽀持远程连接 修改 /etc/redis/redis.conf 修改 bind 127.0.0.1 为 bind 0.0.0.0 修改 protected-mode yes 为 protected-mo…...
[原创](Windows使用技巧): Windwos11如何设置局域网共享访问? (多图详解)
[作者] 常用网名: 猪头三 出生日期: 1981.XX.XX 企鹅交流: 643439947 个人网站: 80x86汇编小站 编程生涯: 2001年~至今[共24年] 职业生涯: 22年 开发语言: C/C++、80x86ASM、Object Pascal、Objective-C、C#、R、Python、PHP、Perl、 开发工具: Visual Studio、Delphi、XCode、…...

Mac 芯片系列 安装cocoapod 教程
安装声明: 本人是在搭梯子的环境下安装成功,前提是必须安装好安装homebrew环境。 1.检测rudy的源 2.查看源(目的:检测rudy的源) gem sources - l 3.移除源(目的:移除rudy自带的源) gem sources --remove https://rubygems.org/ 4.更换源(目的:替换成国…...

智启未来:AI重构制造业供应链的五大革命性突破
一、需求预测:让供应链“未卜先知” 1.1 从经验判断到数据预言 传统供应链依赖人工分析历史数据,但面对市场波动、设备突发故障等不确定性,往往反应滞后。AI通过整合工业物联网(IIoT)传感器数据、生产排程、供应商交…...

Linux进程间通信----简易进程池实现
进程池的模拟实现 1.进程池的原理: 是什么 进程池是一种多进程编程模式,核心思想是先创建好一定数量的子进程用作当作资源,这些进程可以帮助完成任务并且重复利用,避免频繁的进程的创建和销毁的开销。 下面我们举例子来帮助理…...

解锁Java多级缓存:性能飞升的秘密武器
一、引言 文末有彩蛋 在当今高并发、低延迟的应用场景中,传统的单级缓存策略往往难以满足性能需求。随着系统规模扩大,数据访问的瓶颈逐渐显现,如何高效管理缓存成为开发者面临的重大挑战。多级缓存架构应运而生,通过分层缓存设…...