LINUX网络编程API原型详细解析
1. 网络体系
1.1. 简介
网络采用分而治之的方法设计,将网络的功能划分为不同的模块,以分层的形式有机组合在一起。 每层实现不同的功能,其内部实现方法对外部其他层次来说是透明的。每层向上层提供服务,同时使用下层提供的服务 网络体系结构即指网络的层次结构和每层所使用协议的集合 两类非常重要的体系结构:OSI与TCP/IP.
1.1.1. OSI开放系统互联模型
OSI模型相关的协议已经很少使用,但模型本身非常通用 OSI模型是一个理想化的模型,尚未有完整的实现 OSI模型共有七层.
1.1.2. TCP/IP协议族的体系结构
TCP/IP协议是Internet事实上的工业标准。 一共有四层
1.1.3. TCP协议通信模型
1.1.4. TCP/IP协议下的数据包
1.1.5. 数据的封装与传递过程
1.1.6. TCP/IP结构
1.1.7. TCP协议特点
TCP(即传输控制协议):是一种面向连接的传输层协议,它能提供高可靠性通信(即数据无误、数据无丢失、数据无失序、数据无重复到达的通信) 适用情况: 适合于对传输质量要求较高,以及传输大量数据的通信。 在需要可靠数据传输的场合,通常使用TCP协议 MSN/QQ等即时通讯软件的用户登录账户管理相关的功能通常采用TCP协议.
1.1.8. UDP协议特点
UDP(User Datagram Protocol)用户数据报协议,是不可靠的无连接的协议。在数据发送前,因为不需要进行连接,所以可以进行高效率的数据传输。 适用情况: 发送小尺寸数据(如对DNS服务器进行IP地址查询时) 在接收到数据,给出应答较困难的网络中使用UDP。(如:无线网络) 适合于广播/组播式通信中。 MSN/QQ/Skype等即时通讯软件的点对点文本通讯以及音视频通讯通常采用UDP协议 流媒体、VOD、VoIP、IPTV等网络多媒体服务中通常采用UDP方式进行实时数据传输.
1.2. TCP/IP网络编程预备知识
1.2.1. Socket
Socket 是一个编程接口 是一种特殊的文件描述符 (everything in Unix is a file) 并不仅限于TCP/IP协议 面向连接 (Transmission Control Protocol - TCP/IP) 无连接 (User Datagram Protocol -UDP 和 Inter-network Packet Exchange - IPX).
1.2.1.1. Socket类型
流式套接字(SOCK_STREAM) 提供了一个面向连接、可靠的数据传输服务,数据无差错、无重复的发送且按发送顺序接收。内设置流量控制,避免数据流淹没慢的接收方。数据被看作是字节流,无长度限制。 数据报套接字(SOCK_DGRAM) 提供无连接服务。数据包以独立数据包的形式被发送,不提供无差错保证,数据可能丢失或重复,顺序发送,可能乱序接收。 原始套接字(SOCK_RAW) 可以对较低层次协议如IP、ICMP直接访问.
1.2.1.2. Socket的位置
1.2.2. IP地址
IP地址是Internet中主机的标识 Internet中的主机要与别的机器通信必须具有一个IP地址 IP地址为32位(IPv4)或者128位(IPv6) 每个数据包都必须携带目的IP地址和源IP地址,路由器依靠此信息为数据包选择路由 表示形式:常用点分形式,如202.38.64.10,最后都会转换为一个32位的无符号整数。 IP地址分类 子网掩码.
1.2.3. 端口号
为了区分一台主机接收到的数据包应该转交给哪个进程来进行处理,使用端口号来区别 TCP端口号与UDP端口号独立 端口号一般由IANA (Internet Assigned Numbers Authority) 管理 众所周知端口:1~1023(1~255之间为众所周知端口,256~1023端口通常由UNIX系统占用) 注册端口:1024~49150 动态或私有端口:49151~65535.
1.2.4. 字节序
不同类型CPU的主机中,内存存储多字节整数序列有两种方法,称为主机字节序(HBO): 小端序(little-endian) - 低序字节存储在低地址 将低字节存储在起始地址,称为“Little-Endian”字节序,Intel、AMD等采用的是这种方式; 大端序(big-endian)- 高序字节存储在低地址 将高字节存储在起始地址,称为“Big-Endian”字节序,由ARM、Motorola等所采用 网络中传输的数据必须按网络字节序,即大端字节序 在大部分PC机上,当应用进程将整数送入socket前,需要转化成网络字节序;当应用进程从socket取出整数后,要转化成小端字节序.
网络字节序(NBO - Network Byte Order) 使用统一的字节顺序,避免兼容性问题 主机字节序(HBO - Host Byte Order) 不同的机器HBO是不一样的,这与CPU的设计有关 Motorola 68K系列、ARM系列,HBO与NBO是一致的 Intel X86系列,HBO与NBO不一致.
大端(Big-Endian):字节的高位在内存中放在存储单元的起始位置.
1.2.5. 字节序转换函数
把给定系统所采用的字节序称为主机字节序。为了避免不同类别主机之间在数据交换时由于对于字节序的不同而导致的差错,引入了网络字节序。
主机字节序到网络字节序:
u_long htonl (u_long hostlong);
u_short htons (u_short short);
网络字节序到主机字节序:
u_long ntohl (u_long hostlong);
u_short ntohs (u_short short);
1.2.6. IP地址的转换
inet_aton( )
将strptr所指的字符串转换成32位的网络字节序二进制值
#include <arpa/inet.h> int inet_aton(const char *strptr, struct in_addr *addrptr); inet_addr( )
功能同上,返回转换后的地址。
int_addr_t inet_addr(const char *strptr);
inet_ntoa( )
将32位网络字节序二进制地址转换成点分十进制的字符串。
char *inet_ntoa(stuct in_addr inaddr);
inet_pton()
将IPV4/IPV6的地址转换成binary格式
int inet_pton(int af, const char *src, void *dst);
2. 系统调用
2.1. 网络编程相关API
2.1.1. 网络编程常用函数
- socket() 创建套接字
- bind() 绑定本机地址和端口
- connect() 建立连接
- listen() 设置监听端口
- accept() 接受TCP连接
- recv(), read(), recvfrom() 数据接收
- send(), write(), sendto() 数据发送
- close(), shutdown() 关闭套接字
2.1.2. socket创建套接字
int socket(int domain, int type, int protocol);参数说明
domain (协议域):描述: 指定通信的协议域,即通信的地址族。
常见值:
AF_INET: IPv4协议族。
AF_INET6: IPv6协议族。
AF_UNIX 或 AF_LOCAL: 本地通信协议族,用于进程间通信(IPC)。
type (套接字类型):描述: 指定套接字的类型,即通信的语义。
常见值:
SOCK_STREAM: 提供面向连接的、可靠的、双向的、基于字节流的通信(如TCP)。
SOCK_DGRAM: 提供无连接的、不可靠的、基于数据报的通信(如UDP)。
SOCK_RAW: 提供原始网络协议访问。
SOCK_SEQPACKET: 提供面向连接的、可靠的、双向的、基于记录的通信。
protocol (协议):描述: 指定使用的具体协议。通常情况下,可以设置为0,表示使用默认协议。
常见值:
0: 使用默认协议。例如,对于AF_INET和SOCK_STREAM,默认协议是TCP;对于AF_INET和SOCK_DGRAM,默认协议是UDP。
具体协议值可以通过getprotobyname函数获取,但通常情况下设置为0即可。
返回值说明
成功:返回一个非负整数,表示新创建的套接字描述符(socket file descriptor)。
套接字描述符是一个整数,用于在后续的套接字操作中标识该套接字。
失败:返回-1,并设置errno以指示错误类型。
常见的错误码包括:
EAFNOSUPPORT: 指定的协议域不受支持。
EPROTONOSUPPORT: 指定的协议不受支持。
ESOCKTNOSUPPORT: 指定的套接字类型不受支持。
ENOBUFS 或 ENOMEM: 内存不足,无法创建套接字。
2.1.3. 地址相关的数据结构
通用地址结构struct sockaddr{ u_short sa_family; // 地址族, AF_xxxchar sa_data[14]; // 14字节协议地址};Internet协议地址结构struct sockaddr_in{ u_short sin_family; // 地址族, AF_INET,2 bytesu_short sin_port; // 端口,2 bytesstruct in_addr sin_addr; // IPV4地址,4 bytes char sin_zero[8]; // 8 bytes unused,作为填充};
IPv4地址结构
// internet address
struct in_addr
{in_addr_t s_addr; // u32 network address
};
2.1.4. bind绑定本机地址和端口
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数说明
sockfd (套接字描述符):描述: 表示要绑定的套接字的文件描述符。
类型: int
说明: 这个文件描述符通常是通过socket函数创建的。
addr (地址结构体指针):描述: 指向包含地址信息的struct sockaddr结构体的指针。
类型: const struct sockaddr *
说明: 这个结构体的具体类型取决于domain参数(例如,AF_INET使用struct sockaddr_in,AF_INET6使用struct sockaddr_in6)。
示例:
对于IPv4地址,通常使用struct sockaddr_in:struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(8888);
addr.sin_addr.s_addr = inet_addr("192.168.1.100");
对于IPv6地址,通常使用struct sockaddr_in6:struct sockaddr_in6 addr;
addr.sin6_family = AF_INET6;
addr.sin6_port = htons(8888);
inet_pton(AF_INET6, "2001:db8::1", &addr.sin6_addr);
addrlen (地址结构体长度):描述: 指定addr参数指向的地址结构体的长度。
类型: socklen_t
说明: 这个参数通常通过sizeof运算符获取。
示例:
对于struct sockaddr_in:socklen_t addrlen = sizeof(struct sockaddr_in);
对于struct sockaddr_in6:socklen_t addrlen = sizeof(struct sockaddr_in6);
返回值说明
成功:返回0,表示绑定成功。
失败:返回-1,并设置errno以指示错误类型。
常见的错误码包括:
EBADF: sockfd不是一个有效的文件描述符。
ENOTSOCK: sockfd不是一个套接字。
EADDRINUSE: 指定的地址已经被其他套接字使用。
EADDRNOTAVAIL: 指定的地址不可用。
EFAULT: addr指向的内存区域不可访问。
EINVAL: addrlen不正确或addr指向的地址结构体不正确。
EACCES: 权限不足,无法绑定到指定的地址。
2.1.5. 地址结构的一般用法
// 定义并清空 sockaddr_in 类型的变量
memset(&myaddr, 0, sizeof(myaddr)); // 清空 myaddr 结构体// 填充地址信息
myaddr.sin_family = AF_INET; // 设置协议族为 IPv4
myaddr.sin_port = htons(8888); // 设置端口号,并转换为主机字节序到网络字节序
myaddr.sin_addr.s_addr = inet_addr("192.168.1.100"); // 设置服务器 IP 地址// 绑定套接字
if (bind(listenfd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) {perror("bind failed"); // 打印错误信息close(listenfd); // 关闭套接字return -1; // 返回错误码
}
2.1.6. 地址转换函数
unsigned long inet_addr(char *address);address是以’\0’结尾的点分IPv4字符串。该函数返回32位的地址。如果字符串包含的不是合法的IP地址,则函数返回-1。例如:
struct in_addr addr;
addr.s_addr = inet_addr(" 192.168.1.100 ");char* inet_ntoa(struct in_addr address);address是IPv4地址结构,函数返回一指向包含点分IP地址的静态存储区字符指针。如果错误则函数返回NULL
2.1.7. listen设置监听端口
int listen(int sockfd, int backlog);
参数说明
sockfd (套接字描述符):描述: 表示要监听的套接字的文件描述符。
类型: int
说明: 这个文件描述符通常是通过socket函数创建的,并且已经通过bind函数绑定到一个地址和端口。
backlog (最大连接队列长度):描述: 指定等待接受(accept)的连接队列的最大长度。
类型: int
说明:
backlog参数定义了内核为相应套接字排队的最大连接数。
当多个客户端同时尝试连接到服务器时,这些连接会被放入一个队列中等待处理。
如果队列已满,新的连接请求可能会被拒绝。
常见的backlog值为5、10或20,具体值可以根据实际需求调整。
返回值说明
成功:返回0,表示监听成功。
失败:返回-1,并设置errno以指示错误类型。
常见的错误码包括:
EBADF: sockfd不是一个有效的文件描述符。
ENOTSOCK: sockfd不是一个套接字。
EOPNOTSUPP: sockfd不支持监听操作。
EADDRINUSE: 地址已经被其他套接字使用。
EINVAL: sockfd已经处于监听状态,或者backlog参数无效。
EACCES: 权限不足,无法监听指定的地址。
注意:完成listen()调用后,socket变成了监听socket(listening socket).
2.1.8. accept接受TCP连接
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
参数说明
sockfd (监听套接字描述符):描述: 表示要接受连接的监听套接字的文件描述符。
类型: int
说明: 这个文件描述符通常是通过socket函数创建的,并且已经通过bind函数绑定到一个地址和端口,然后通过listen函数设置为监听状态。
addr (客户端地址结构体指针):描述: 指向一个struct sockaddr类型的结构体,用于存储客户端的地址信息。
类型: struct sockaddr *
说明:
如果不需要客户端的地址信息,可以将此参数设置为NULL。
如果需要客户端的地址信息,需要先定义一个适当的结构体(如struct sockaddr_in),然后将其强制转换为struct sockaddr *类型。
例如,对于IPv4地址,可以使用struct sockaddr_in:struct sockaddr_in client_addr;
socklen_t client_addr_len = sizeof(client_addr);
int client_fd = accept(listenfd, (struct sockaddr *)&client_addr, &client_addr_len);
addrlen (地址结构体长度指针):描述: 指向一个socklen_t类型的变量,用于指定addr参数指向的地址结构体的长度。
类型: socklen_t *
说明:
在调用accept之前,需要初始化addrlen为地址结构体的实际大小。
例如,对于struct sockaddr_in,可以这样做:struct sockaddr_in client_addr;
socklen_t client_addr_len = sizeof(client_addr);
int client_fd = accept(listenfd, (struct sockaddr *)&client_addr, &client_addr_len);
在accept返回后,addrlen会被设置为实际存储的客户端地址信息的长度。
返回值说明
成功:返回一个新的套接字描述符,用于与客户端通信。
失败:返回-1,并设置errno以指示错误类型。
常见的错误码包括:
EBADF: sockfd不是一个有效的文件描述符。
ENOTSOCK: sockfd不是一个套接字。
EOPNOTSUPP: sockfd不支持接受操作。
ECONNABORTED: 连接被中断。
EINTR: 被信号中断。
EMFILE: 进程打开的文件描述符数量达到限制。
ENFILE: 系统打开的文件描述符数量达到限制。
ENOMEM: 内存不足,无法创建新的套接字。
2.1.9. connect 建立连接
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数说明
sockfd (套接字描述符):描述: 表示要连接的套接字的文件描述符。
类型: int
说明: 这个文件描述符通常是通过socket函数创建的,但尚未连接到任何远程地址。
addr (服务器地址结构体指针):描述: 指向一个struct sockaddr类型的结构体,用于存储服务器的地址信息。
类型: const struct sockaddr *
说明:
必须提供一个有效的服务器地址结构体,通常使用struct sockaddr_in(对于IPv4)或struct sockaddr_in6(对于IPv6)。
例如,对于IPv4地址,可以使用struct sockaddr_in:
c
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8888);
server_addr.sin_addr.s_addr = inet_addr("192.168.1.100");
对于IPv6地址,可以使用struct sockaddr_in6:
c
struct sockaddr_in6 server_addr;
server_addr.sin6_family = AF_INET6;
server_addr.sin6_port = htons(8888);
inet_pton(AF_INET6, "2001:db8::1", &server_addr.sin6_addr);
addrlen (地址结构体长度):描述: 指定addr参数指向的地址结构体的长度。
类型: socklen_t
说明: 这个参数通常通过sizeof运算符获取。
示例:
对于struct sockaddr_in:socklen_t addrlen = sizeof(struct sockaddr_in);
对于struct sockaddr_in6:socklen_t addrlen = sizeof(struct sockaddr_in6);
返回值说明
成功:返回0,表示连接成功。
失败:返回-1,并设置errno以指示错误类型。
常见的错误码包括:
EBADF: sockfd不是一个有效的文件描述符。
ENOTSOCK: sockfd不是一个套接字。
EADDRINUSE: 本地地址已经被其他套接字使用。
EADDRNOTAVAIL: 本地地址不可用。
EAFNOSUPPORT: 地址族不支持。
EALREADY: 套接字是非阻塞的,并且连接操作正在进行中。
ECONNREFUSED: 连接被服务器拒绝。
EISCONN: 套接字已经连接。
ENETUNREACH: 网络不可达。
ETIMEDOUT: 连接超时。
EHOSTUNREACH: 主机不可达。
EINPROGRESS: 套接字是非阻塞的,并且连接操作正在进行中。
EINTR: 被信号中断。
EACCES: 权限不足,无法连接到指定的地址。
2.1.10. send数据发送
ssize_t send(int socket, const void *buffer, size_t length, int flags);
参数说明
socket (套接字描述符):描述: 表示要发送数据的套接字的文件描述符。
类型: int
说明: 这个文件描述符通常是通过socket函数创建的,并且已经通过connect函数连接到远程地址(对于TCP)或准备好发送数据(对于UDP)。
buffer (数据缓冲区):描述: 指向包含要发送数据的缓冲区的指针。
类型: const void *
说明:
buffer指向的数据可以是任意类型,但通常是一个字节数组。
使用const void *表示send函数不会修改缓冲区中的数据。
length (数据长度):描述: 指定要发送的数据长度(以字节为单位)。
类型: size_t
说明:
length参数指定buffer中要发送的字节数。
通常使用strlen函数获取字符串的长度,但要注意strlen不包括字符串结束符\0。
flags (标志位):描述: 指定发送操作的行为。
类型: int
说明:
flags参数可以是0,表示默认行为。
常见的标志位包括:
MSG_DONTROUTE: 不使用路由表查找目标地址。
MSG_OOB: 发送带外数据(仅适用于支持带外数据的协议,如TCP)。
MSG_NOSIGNAL: 如果发送操作导致对端关闭连接,不发送SIGPIPE信号。
MSG_CONFIRM: 确认连接(仅适用于某些协议)。
返回值说明
成功:返回实际发送的字节数(ssize_t类型)。
返回值可能小于length,表示部分数据已发送。
失败:返回-1,并设置errno以指示错误类型。
常见的错误码包括:
EBADF: socket不是一个有效的文件描述符。
ENOTSOCK: socket不是一个套接字。
EAGAIN 或 EWOULDBLOCK: 套接字是非阻塞的,并且当前不可写。
EDESTADDRREQ: 目标地址未指定(对于无连接的套接字,如UDP)。
EINTR: 发送操作被信号中断。
EINVAL: flags参数无效。
EISCONN: 套接字已经连接(对于无连接的套接字,如UDP)。
EMSGSIZE: 发送的数据长度超过协议允许的最大值。
ENOBUFS 或 ENOMEM: 内存不足,无法发送数据。
ENOTCONN: 套接字未连接(对于面向连接的套接字,如TCP)。
EPIPE: 对端关闭了连接(仅适用于面向连接的套接字,如TCP),并且flags未设置MSG_NOSIGNAL。
2.1.11. recv数据接收
ssize_t recv(int socket, void *buffer, size_t length, int flags);
参数说明
socket (套接字描述符):描述: 表示要接收数据的套接字的文件描述符。
类型: int
说明: 这个文件描述符通常是通过socket函数创建的,并且已经通过bind和listen函数设置为监听状态(对于TCP服务器),或者已经通过connect函数连接到远程地址(对于TCP客户端或UDP套接字)。
buffer (数据缓冲区):描述: 指向用于存储接收到的数据的缓冲区的指针。
类型: void *
说明:
buffer指向的数据可以是任意类型,但通常是一个字节数组。
recv函数会将接收到的数据存储在这个缓冲区中。
length (缓冲区长度):描述: 指定缓冲区的最大长度(以字节为单位),即最多可以接收的数据量。
类型: size_t
说明:
length参数指定buffer可以存储的最大字节数。
通常设置为缓冲区的实际大小减1,以确保有足够的空间存储字符串结束符\0(如果需要)。
flags (标志位):描述: 指定接收操作的行为。
类型: int
说明:
flags参数可以是0,表示默认行为。
常见的标志位包括:
MSG_DONTWAIT: 非阻塞模式,如果数据不可用,立即返回EAGAIN或EWOULDBLOCK。
MSG_OOB: 接收带外数据(仅适用于支持带外数据的协议,如TCP)。
MSG_PEEK: 查看数据而不从缓冲区中移除。
MSG_TRUNC: 返回实际接收的数据长度,即使数据被截断。
MSG_WAITALL: 等待直到接收指定数量的数据(仅适用于面向连接的套接字,如TCP)。
返回值说明
成功:返回实际接收的字节数(ssize_t类型)。
返回值可能小于length,表示部分数据已接收。
失败:返回-1,并设置errno以指示错误类型。
常见的错误码包括:
EBADF: socket不是一个有效的文件描述符。
ENOTSOCK: socket不是一个套接字。
EAGAIN 或 EWOULDBLOCK: 套接字是非阻塞的,并且当前没有数据可读。
EINTR: 接收操作被信号中断。
EINVAL: flags参数无效。
ENOMEM: 内存不足,无法接收数据。
ENOTCONN: 套接字未连接(对于面向连接的套接字,如TCP)。
EFAULT: buffer指向的内存区域不可访问。
2.1.12. read数据接收/write数据发送
read()和write()经常会代替recv()和send(),通常情况下,看自己的的偏好使用read()/write()和recv()/send()时最好统一.
ssize_t read(int fd, void *buf, size_t count);
参数说明
fd (文件描述符):描述: 表示要读取数据的文件描述符。
类型: int
说明: 这个文件描述符可以是任何类型的文件描述符,包括套接字、文件、管道等。
buf (数据缓冲区):描述: 指向用于存储读取数据的缓冲区的指针。
类型: void *
说明:
buf指向的数据可以是任意类型,但通常是一个字节数组。
read函数会将读取的数据存储在这个缓冲区中。
count (数据长度):描述: 指定要读取的最大字节数。
类型: size_t
说明:
count参数指定buf可以存储的最大字节数。
实际读取的字节数可能小于count,具体取决于文件或套接字的状态。
返回值说明
成功:返回实际读取的字节数(ssize_t类型)。
返回值可能小于count,表示部分数据已读取。
失败:返回-1,并设置errno以指示错误类型。
常见的错误码包括:
EBADF: fd不是一个有效的文件描述符。
EAGAIN 或 EWOULDBLOCK: 文件描述符是非阻塞的,并且当前没有数据可读。
EINTR: 读取操作被信号中断。
EINVAL: buf指向的内存区域不可访问。
EIO: I/O 错误。
EFAULT: buf指向的内存区域不可访问。
EISDIR: fd是一个目录。
ECONNRESET: 连接被对端重置(仅适用于套接字)。
ssize_t write(int fd, const void *buf, size_t count);
参数说明
fd (文件描述符):描述: 表示要写入数据的文件描述符。
类型: int
说明: 这个文件描述符可以是任何类型的文件描述符,包括套接字、文件、管道等。
buf (数据缓冲区):描述: 指向包含要写入数据的缓冲区的指针。
类型: const void *
说明:
buf指向的数据可以是任意类型,但通常是一个字节数组。
write函数不会修改缓冲区中的数据。
count (数据长度):描述: 指定要写入的最大字节数。
类型: size_t
说明:
count参数指定buf中要写入的字节数。
实际写入的字节数可能小于count,具体取决于文件或套接字的状态。
返回值说明
成功:返回实际写入的字节数(ssize_t类型)。
返回值可能小于count,表示部分数据已写入。
失败:返回-1,并设置errno以指示错误类型。
常见的错误码包括:
EBADF: fd不是一个有效的文件描述符,或者不是打开用于写入的文件描述符。
EAGAIN 或 EWOULDBLOCK: 文件描述符是非阻塞的,并且当前不可写。
EINTR: 写入操作被信号中断。
EINVAL: buf指向的内存区域不可访问。
EIO: I/O 错误。
EFAULT: buf指向的内存区域不可访问。
ENOSPC: 设备上没有足够的空间写入数据。
EPIPE: 对端关闭了连接(仅适用于套接字),并且fd未设置O_NONBLOCK。
示例代码
2.1.13. sendto数据发送/recvfrom数据接收
这两个函数一般在使用UDP协议时使用.
ssize_t sendto(int socket, const void *message, size_t length, int flags, const struct sockaddr *dest_addr, socklen_t dest_len);
参数说明
socket (套接字描述符):描述: 表示要发送数据的套接字的文件描述符。
类型: int
说明: 这个文件描述符通常是通过socket函数创建的,并且可以是UDP套接字或未连接的TCP套接字。
message (数据缓冲区):描述: 指向包含要发送数据的缓冲区的指针。
类型: const void *
说明:
message指向的数据可以是任意类型,但通常是一个字节数组。
sendto函数不会修改缓冲区中的数据。
length (数据长度):描述: 指定要发送的数据长度(以字节为单位)。
类型: size_t
说明:
length参数指定message中要发送的字节数。
通常使用strlen函数获取字符串的长度,但要注意strlen不包括字符串结束符\0。
flags (标志位):描述: 指定发送操作的行为。
类型: int
说明:
flags参数可以是0,表示默认行为。
常见的标志位包括:
MSG_DONTROUTE: 不使用路由表查找目标地址。
MSG_OOB: 发送带外数据(仅适用于支持带外数据的协议,如TCP)。
MSG_NOSIGNAL: 如果发送操作导致对端关闭连接,不发送SIGPIPE信号。
MSG_CONFIRM: 确认连接(仅适用于某些协议)。
dest_addr (目标地址结构体指针):描述: 指向包含目标地址信息的struct sockaddr类型的结构体的指针。
类型: const struct sockaddr *
说明:
这个结构体的具体类型取决于socket的协议族(例如,AF_INET使用struct sockaddr_in,AF_INET6使用struct sockaddr_in6)。
例如,对于IPv4地址,通常使用struct sockaddr_in:struct sockaddr_in dest_addr;
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(8888);
dest_addr.sin_addr.s_addr = inet_addr("192.168.1.100");
对于IPv6地址,通常使用struct sockaddr_in6:struct sockaddr_in6 dest_addr;
dest_addr.sin6_family = AF_INET6;
dest_addr.sin6_port = htons(8888);
inet_pton(AF_INET6, "2001:db8::1", &dest_addr.sin6_addr);
dest_len (目标地址结构体长度):描述: 指定dest_addr参数指向的地址结构体的长度。
类型: socklen_t
说明: 这个参数通常通过sizeof运算符获取。
示例:
对于struct sockaddr_in:socklen_t dest_len = sizeof(struct sockaddr_in);
对于struct sockaddr_in6:socklen_t dest_len = sizeof(struct sockaddr_in6);
返回值说明
成功:返回实际发送的字节数(ssize_t类型)。
返回值可能小于length,表示部分数据已发送。
失败:返回-1,并设置errno以指示错误类型。
常见的错误码包括:
EBADF: socket不是一个有效的文件描述符。
ENOTSOCK: socket不是一个套接字。
EAGAIN 或 EWOULDBLOCK: 套接字是非阻塞的,并且当前不可写。
EDESTADDRREQ: 目标地址未指定(对于无连接的套接字,如UDP)。
EINTR: 发送操作被信号中断。
EINVAL: flags参数无效。
EMSGSIZE: 发送的数据长度超过协议允许的最大值。
ENOBUFS 或 ENOMEM: 内存不足,无法发送数据。
ENOTCONN: 套接字未连接(对于面向连接的套接字,如TCP)。
EPIPE: 对端关闭了连接(仅适用于面向连接的套接字,如TCP),并且flags未设置MSG_NOSIGNAL。
ssize_t recvfrom(int socket, void *buffer, size_t length, int flags, struct sockaddr *address, socklen_t *address_len);
参数说明
socket (套接字描述符):描述: 表示要接收数据的套接字的文件描述符。
类型: int
说明: 这个文件描述符通常是通过socket函数创建的,并且可以是UDP套接字或未连接的TCP套接字。
buffer (数据缓冲区):描述: 指向用于存储接收到的数据的缓冲区的指针。
类型: void *
说明:
buffer指向的数据可以是任意类型,但通常是一个字节数组。
recvfrom函数会将接收到的数据存储在这个缓冲区中。
length (缓冲区长度):描述: 指定缓冲区的最大长度(以字节为单位),即最多可以接收的数据量。
类型: size_t
说明:
length参数指定buffer可以存储的最大字节数。
通常设置为缓冲区的实际大小减1,以确保有足够的空间存储字符串结束符\0(如果需要)。
flags (标志位):描述: 指定接收操作的行为。
类型: int
说明:
flags参数可以是0,表示默认行为。
常见的标志位包括:
MSG_DONTWAIT: 非阻塞模式,如果数据不可用,立即返回EAGAIN或EWOULDBLOCK。
MSG_OOB: 接收带外数据(仅适用于支持带外数据的协议,如TCP)。
MSG_PEEK: 查看数据而不从缓冲区中移除。
MSG_TRUNC: 返回实际接收的数据长度,即使数据被截断。
MSG_WAITALL: 等待直到接收指定数量的数据(仅适用于面向连接的套接字,如TCP)。
address (源地址结构体指针):描述: 指向一个struct sockaddr类型的结构体,用于存储发送方的地址信息。
类型: struct sockaddr *
说明:
如果不需要发送方的地址信息,可以将此参数设置为NULL。
如果需要发送方的地址信息,需要先定义一个适当的结构体(如struct sockaddr_in),然后将其强制转换为struct sockaddr *类型。
例如,对于IPv4地址,可以使用struct sockaddr_in:struct sockaddr_in src_addr;
socklen_t src_addr_len = sizeof(src_addr);
ssize_t bytes_received = recvfrom(sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&src_addr, &src_addr_len);
对于IPv6地址,可以使用struct sockaddr_in6:struct sockaddr_in6 src_addr;
socklen_t src_addr_len = sizeof(src_addr);
ssize_t bytes_received = recvfrom(sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&src_addr, &src_addr_len);
address_len (源地址结构体长度指针):描述: 指向一个socklen_t类型的变量,用于指定address参数指向的地址结构体的长度。
类型: socklen_t *
说明:
在调用recvfrom之前,需要初始化address_len为地址结构体的实际大小。
例如,对于struct sockaddr_in,可以这样做:struct sockaddr_in src_addr;
socklen_t src_addr_len = sizeof(src_addr);
ssize_t bytes_received = recvfrom(sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&src_addr, &src_addr_len);
在recvfrom返回后,address_len会被设置为实际存储的发送方地址信息的长度。
返回值说明
成功:返回实际接收的字节数(ssize_t类型)。
返回值可能小于length,表示部分数据已接收。
失败:返回-1,并设置errno以指示错误类型。
常见的错误码包括:
EBADF: socket不是一个有效的文件描述符。
ENOTSOCK: socket不是一个套接字。
EAGAIN 或 EWOULDBLOCK: 套接字是非阻塞的,并且当前没有数据可读。
EINTR: 接收操作被信号中断。
EINVAL: flags参数无效。
ENOMEM: 内存不足,无法接收数据。
ENOTCONN: 套接字未连接(对于面向连接的套接字,如TCP)。
EFAULT: buffer或address指向的内存区域不可访问。
2.1.14. close关闭套接字
关闭双向通讯.
int close(int sockfd);
参数说明
sockfd (文件描述符):
描述: 表示要关闭的文件描述符。
类型: int
说明: 这个文件描述符可以是任何类型的文件描述符,包括套接字、文件、管道等。
返回值说明
成功:返回0,表示文件描述符关闭成功。
失败:返回-1,并设置errno以指示错误类型。
常见的错误码包括:
EBADF: sockfd不是一个有效的文件描述符。
EINTR: 关闭操作被信号中断。
2.1.15. shutdown关闭套接字
TCP连接是双向的(是可读写的),当我们使用close时,会把读写通道都关闭,有时侯我们希望只关闭一个方向,这个时候我们可以使用shutdown。 针对不同的howto,系统回采取不同的关闭方式。
int shutdown(int sockfd, int howto);
参数说明
sockfd (套接字描述符):描述: 表示要关闭的套接字的文件描述符。
类型: int
说明: 这个文件描述符通常是通过socket函数创建的,并且已经通过bind和listen函数设置为监听状态(对于TCP服务器),或者已经通过connect函数连接到远程地址(对于TCP客户端或UDP套接字)。
howto (关闭方式):描述: 指定关闭套接字的方式。
类型: int
说明:
howto参数可以是以下值之一:
SHUT_RD: 关闭套接字的接收端。后续对套接字的读操作将立即返回0(表示EOF)。
SHUT_WR: 关闭套接字的发送端。后续对套接字的写操作将返回EPIPE信号(对于TCP)。
SHUT_RDWR: 关闭套接字的接收端和发送端。等同于调用close(sockfd)。
返回值说明
成功:返回0,表示关闭操作成功。
失败:返回-1,并设置errno以指示错误类型。
常见的错误码包括:
EBADF: sockfd不是一个有效的文件描述符。
ENOTSOCK: sockfd不是一个套接字。
EINVAL: howto参数无效。
ENOTCONN: 套接字未连接(对于面向连接的套接字,如TCP)。
相关文章:
LINUX网络编程API原型详细解析
1. 网络体系 1.1. 简介 网络采用分而治之的方法设计,将网络的功能划分为不同的模块,以分层的形式有机组合在一起。 每层实现不同的功能,其内部实现方法对外部其他层次来说是透明的。每层向上层提供服务,同时使用下层提供…...
Android 13 Launcher3最近任务列表“全部清除“按钮位置优化实战
一、问题背景与实现难点 在Android 13横屏设备开发中,系统默认将最近任务列表的"全部清除"按钮布局在屏幕左侧,这与用户习惯的底部布局存在明显差异。相较于Android 8.1时代SystemUI模块的实现,Android 13将相关逻辑迁移至Launche…...
docker最新源,及遇到问题+处理
目前国内可用Docker镜像源汇总(截至2025年3月) - CoderJia 遇到问题: Error response from daemon: Get "https://registry-1.docker.io/v2/": dial tcp: lookup registry-1.docker.io on [::1]:53: read udp [::1]:13287->[:…...
Python简单爬虫实践案例
学习目标 能够知道Web开发流程 能够掌握FastAPI实现访问多个指定网页 知道通过requests模块爬取图片 知道通过requests模块爬取GDP数据 能够用pyecharts实现饼图 能够知道logging日志的使用 一、基于FastAPI之Web站点开发 1、基于FastAPI搭建Web服务器 # 导入FastAPI模…...
统信UOS中使用Vscode编程
写在前面:统信UOS其实就是套壳的Linux系统,所以有问题如果搜不到解决方法,可以参考Linux下的解决方法。 1.环境配置 Vscode : 1.85.0 Vscode就直接下载安装就行,然后安装插件:Volar、中文汉化包 node:18…...
C#从入门到精通(1)
目录 第一章 C#与VS介绍 第二章 第一个C#程序 (1)C#程序基本组成 1.命名空间 2.类 3.Main方法 4.注释 5.语句 6.标识符及关键字 (2)程序编写规范 1.代码编写规则 2.程序命名方法 3.元素命名规范 第三章 变量 &…...
openharmony中hilog实证记录说明(3.1和5.0版本)
每次用这个工具hilog都有一些小用法记不清,需要花一些时间去查去分析使用方法,为了给丰富多彩的生活留出更多的时间,所以汇总整理共享来了,它来了它来了~~~~~~~~~ 开始是想通过3.1来汇总的,但实际测试发现openharmony…...
飞书 设计智能字段:通过“字段类型”添加AI功能列
在飞书多维表格中,通过“字段类型”添加AI功能列的核心逻辑是将AI模型能力与结构化数据结合,实现自动化内容生成与信息处理。以下是具体操作步骤及关键要点,结合实际应用场景说明: 一、基础操作步骤 创建多维表格 登录飞书&#x…...
Cannot find module @rollup/rollup-win32-x64-msvc
方法1 在package.json中添加postinstall: "scripts": {"postinstall": "node -e \"const { platform } process; if (platform win32) { require(child_process).execSync(npm install rollup/rollup-win32-x64-msvc, { stdio: inherit });…...
Docker和Dify学习笔记
文章目录 1 docker学习1.1 基本命令使用1.1.1 docker ps查看当前正在运行的镜像1.1.2 docker stop停止容器1.1.3 docker compose容器编排1.1.4 docker网络[1] 进入到容器里面敲命令[2] docker network ls[3] brige网络模式下容器访问宿主机的方式 2 Dify的安装和基础使用2.1 下…...
【AIGC】Win10系统极速部署Docker+Ragflow+Dify
【AIGC】WIN10仅3步部署DockerRagflowDify 一、 Docker快速部署1.F2进入bios界面,按F7设置开启VMX虚拟化技术。保存并退出。2.打开控制面板配置开启服务3.到官网下载docker安装包,一键安装(全部默认勾选) 二、 RagFlow快速部署1.确…...
Oracle ASM 磁盘组冗余策略
Oracle ASM 磁盘组冗余策略 1. 外部冗余(External Redundancy)2. 普通冗余(Normal Redundancy)3. 高冗余(High Redundancy)关键注意事项如何选择合适的策略? Oracle ASM(Automatic S…...
C++ 数据结构
C++ 数据结构 概述 C++作为一种强大的编程语言,在软件开发领域有着广泛的应用。数据结构作为C++编程中不可或缺的一部分,它决定了程序的性能和效率。本文将详细介绍C++中的常见数据结构,包括其定义、特点以及在实际应用中的使用方法。 常见数据结构 1. 数组 数组是一种…...
Unity NodeCanvas AI使用笔记
扩展: 1. 输入输出参数限制,增加描述,根据接口判断类型限制 2.选择节点,遍历节点,行为节点 3.行为节点 行为执行的时候有互斥关系,加入一个queue,最后执行 4.NodeCanvas的参数传参可以由上个节点传到下个节…...
(* IOB = “FORCE“ *) 的使用分享
在Xilinx FPGA设计中,IOBFORCE是一个与输入输出块(IOB)相关的属性设置。这个设置主要用于控制逻辑是否被推入到IOB(Input/Output Block)中,即FPGA芯片边缘的I/O引脚附近的专用硬件资源。使用IOB属性可以帮助…...
【大语言模型_7】利用ragas框架评测rag系统指标
一、介绍 ragas是一个用来评估RAG系统的框架,允许不在依赖人工注释的情况下,通过一套指标评估检索模块和生成模块的性能及其质量。 二、准备 数据准备:需要准备评估数据集,数据集格式如下 [{"question": "安全智…...
adb常用的命令
1. 查看adb版本 adb version 2. 将apk安装包安装到手机/模拟器上 adb install apk路径 3. 获取apk包名和界面名 包名(package):决定程序的唯一性 界面名(activity):一个界面界面名,对应一个界面…...
手动集成sqlite的方法
注意到sqlite有backup方法(https://www.sqlite.org/backup.html)。 也注意到android中sysroot下,没有sqlite3的库,也没有相关头文件。 如果要使用 sqlite 的backup,那么就需要手动集成sqlite代码到项目中。可以如下操…...
自然语言处理(NLP)技术
人工智能(Artificial Intelligence,AI)是一种模拟人类智能思维过程的技术,它在现代科技中的应用非常广泛,涉及诸多领域,如自然语言处理、计算机视觉、机器学习、数据分析等。以下是人工智能在现代科技中的应…...
【GPT入门】第25课 掌握 LangChain:链式调用的奥秘、特性与使用示例
【GPT入门】第25课 掌握 LangChain:链式调用的奥秘、特性与使用示例 语法解释各部分性质链式调用的性质调用方式注意事项 语法解释 你给出的代码 is_duplicated_chain (check_duplicated | model | parser) 运用了 LangChain 里的链式调用语法。在 LangChain 中&a…...
机器学习之DBSCAN算法详解
文章目录 引言1. DBSCAN算法概述2.DBSCAN算法的基本概念2.1 ε-邻域2.2 核心点(Core Point)2.3 边界点(Border Point)2.4 噪声点(Noise Point)2.5 直接密度可达(Directly Density-Reachable&…...
借助vite来优化前端性能
Vite 是一个现代化的前端构建工具,凭借其基于原生 ES 模块的开发服务器和高效的构建能力,可以显著优化前端性能。 一、开发环境优化 1.快速启动与热更新 Vite 利用浏览器对 ES 模块的原生支持,在开发环境中无需打包,直接按需加载…...
[工控机安全] 使用DriverView快速排查不可信第三方驱动(附详细图文教程)
导语: 在工业控制领域,设备驱动程序的安全性至关重要。第三方驱动可能存在兼容性问题、安全漏洞甚至恶意代码,威胁设备稳定运行。本文将手把手教你使用 DriverView工具,高效完成工控机驱动安全检查,精准识别可疑驱动&a…...
Execution failed for task ‘:path_provider_android:compileDebugJavaWithJavac‘.
What went wrong: Execution failed for task ‘:path_provider_android:compileDebugJavaWithJavac’. Could not resolve all files for configuration ‘:path_provider_android:androidJdkImage’. Failed to transform core-for-system-modules.jar to match attributes {…...
基于SpringBoot的社区/物业管理系统
项目介绍 平台采用B/S结构,后端采用主流的SpringBoot语言进行开发,前端采用主流的Vue.js进行开发。是一个综合的社区/物业管理系统。 整个平台包括前台和后台两个部分。 - 前台功能包括:小区信息、社区论坛、社区公告、社区留言板、个人中心。…...
vmware下linux无法上网解决方法
首先,打开打开"编辑" “虚拟网络编辑器”,并将"桥接"方式的网卡选择为主机上网的网卡。 虚拟机中,设置IP地址为主机网卡同样子网下的ip地址: 并且要选择桥接模式!注意如下图,"复制物理连接状…...
【数据库备份】docker中数据库备份脚本——MySql备份脚本
docker中数据库备份脚本——MySql备份脚本 #!/bin/bash# MySQL数据库信息 DB_USER"root" DB_PASSWORD"你的密码"# 备份保存主目录 BACKUP_ROOT"/data/data_backup/mysql"# 最多保留的备份日期文件夹数 MAX_DATE_FOLDERS15# 数组包含要备份的数据…...
SpringBoot 第二课(Ⅰ) 整合springmvc(详解)
目录 一、SpringBoot对静态资源的映射规则 1. WebJars 资源访问 2. 静态资源访问 3. 欢迎页配置 二、SpringBoot整合springmvc 概述 Spring MVC组件的自动配置 中央转发器(DispatcherServlet) 控制器(Controller) 视图解…...
centos家用笔记
改用阿里云yum源 因CentOS7已经停止维护,原有的yum源也无法使用,在国内,改用阿里云yum源是个方便的选择。 cd /etc/yum.repos.d/ mkdir backup mv Cent* backup wget http://mirrors.aliyun.com/repo/Centos-7.repo mv Centos-7.repo Cen…...
数据可视化(matplotlib)-------辅助图标的设置
目录 一、认识图表常用的辅助元素 坐标轴 二、设置坐标轴的标签、刻度范围和刻度标签 (一)、设置坐标轴的标签 1、xlabel()------设置x轴标签 2、ylabel()------设置y轴标签 (二) 、设置刻度范围和刻度标签 1、xlim()和ylim()函数分别可…...
15-双链表-双链表基本操作
题目 来源 827. 双链表 - AcWing题库 思路 此题我只想说,千万千万别漏了头结点和尾结点,不然根本查不出来是哪里出了问题,因为传入的k会有问题;最左边插入,相当于是在头结点的右边插入(也就是0号节点的右…...
HTTP和RPC的区别
RPC和 HTTP是两种常见的通信方式,它们在设计目标、使用场景和技术实现上有显著区别。以下是它们的详细对比: 1. 定义与核心思想 特性RPCHTTPRemote Procedure Call远程过程调用HyperText Transfer Protocol超文本传输协议定义一种协议或框架࿰…...
【Linux内核系列】:动静态库详解
🔥 本文专栏:Linux 🌸作者主页:努力努力再努力wz 💪 今日博客励志语录: 有些鸟儿是注定是关不住的,因为它们的每一片羽翼都沾满了自由的光辉 ★★★ 本文前置知识: 编译与链接的过程…...
【IROS 2025】CMU提出路径规划器PIPE:机器人探索效率提升14.6%,地图准确率提高9.3%!
在自主机器人探索未知环境的研究中,如何高效地规划路径、最大化信息获取,一直是一个核心问题。传统的方法往往仅在离散的路径点上计算信息增益,而缺乏对整个路径信息获取的综合考量,从而可能导致探索低效甚至错误的规划决策。近日…...
《笔记》Android 获取第三方应用及查看应用信息、apk大小、缓存、存储,以及第三方清除缓存
获取应用相关信息: PS:manifest标签中设置以下属性表示系统应用 android:process"system" android:sharedUserId"android.uid.system" //获取所有应用(非系统apk,有些应用获取不到) List<ApplicationInf…...
npm 安装 pnpm 的详细步骤及注意事项
一、安装步骤 1.全局安装 pnpm npm install -g pnpm2.验证安装 pnpm -v输出版本号即表示安装成功。 二、升级 pnpm 若已安装旧版本,可通过以下命令升级: npm install -g pnpmlatest三、配置镜像加速 设置淘宝镜像 pnpm config set registry http…...
大白话详细解读React框架的diffing算法
1. Diffing 算法是什么? Diffing 算法是 React 用来比较虚拟 DOM(Virtual DOM)树的一种算法。它的作用是找出前后两次渲染之间的差异(diff),然后只更新这些差异部分,而不是重新渲染整个页面。 …...
【架构】单体架构 vs 微服务架构:如何选择最适合你的技术方案?
文章目录 ⭐前言⭐一、架构设计的本质差异🌟1、代码与数据结构的对比🌟2、技术栈的灵活性 ⭐二、开发与维护的成本博弈🌟1、开发效率的阶段性差异🌟2、维护成本的隐形陷阱 ⭐三、部署与扩展的实战策略🌟1、部署模式的本…...
面试redis常被问到的面试题含答案
什么是Redis?它的特点是什么? Redis是一个开源的内存数据库,用于存储数据并支持多种数据结构(如字符串、哈希、列表、集合、有序集合等)。其特点包括高性能、支持持久化、数据结构丰富、原子性操作、支持事务等。 Red…...
Asp.net Core API 本地化
本文是一个demo,演示了如何根据用户接口查询字段(正常放header中),设置当前culture,并获取当前culture的key value给用户提示 创建Resources文件夹,添加以下三个文件 其中ExceptionUnuse 是一个空的类,供IStringLocalizer使用&a…...
使用Java实现Oracle表结构转换为PostgreSQL的示例方案(AI)
核心代码 import java.sql.*; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map;public class OracleToPGConverter {// 类型映射表private static final Map<String, String> TYPE_MAPPING new HashMap<>()…...
win32汇编环境,网络编程入门之八
;在上一教程里,我们学习了简单的处理服务器返回的数据 ;在这一教程里,我们了解一下,当连接上网站后,应该发送什么数据过去的问题 ;这里有个简单的方式学习,以下是一个示例 ;我们上网的时候可以用谷歌浏览器,…...
Java EE 进阶:MyBatis
MyBatis是一个优秀的持久化框架,用于简化JDBC的开发。 持久层就是持久化访问的层,就是数据访问层(Dao),用于访问数据库的。 MyBatis使用的准备工作 创建项目,导入mybatis的启动依赖,mysql的驱…...
Linux驱动开发基础(can)
目录 1.can的介绍 2.can的硬件连接 2.1 CPU自带can控制器 2.2 CPU没有can控制器 3.电气属性 4.can的特点 5.can协议 5.1 can的种类 5.2 数据帧 5.2.1 标准数据帧格式 5.3.1 扩展数据帧格式 5.3 遥控帧 5.4 错误帧 5.5 过载帧 5.6 帧间隔 5.7 位填充 5.8 位时…...
Linux 命令行整理(完善中)
文件类 查看文件类 cat 用于连接文件并打印到标准输出设备上,可用于查看文件内容.(短文件) use:cat example.txtmore 分页的形式显示文件内容,适合查看较长的文件(长) use: more example.txtless 也是分页查看文件内容ÿ…...
回调方法传值汇总
<template v-slot"scope"><el-switch v-model"scope.row.open" change"(p1) > changeOpen(p1, scope.row)"></el-switch></template>公域流量 多选 selection-change“val > multipleSelection val”...
分享一个精灵图生成和拆分的实现
概述 精灵图(Sprite)是一种将多个小图像合并到单个图像文件中的技术,广泛应用于网页开发、游戏开发和UI设计中。在MapboxGL中,跟之配套的还有一个json文件用来记录图标的大小和位置。本文分享基于Node和sharp库实现精灵图的合并与…...
python中的min函数的key的用法 - abs绝对值
前言 继续上一章节提及的 Python 中 min() 函数的用法,包括其基本语法、处理列表、接收多个参数 这个章节将补充一些新的知识点例如: min函数中key的另一种用法abs绝对值 min(iterable, *iterables, keyNone, defaultNone) 知识点 key 参数 key 是一个可选参数…...
我开发的PDF转WORD免费工具
ZhouShengHuan 欢迎小伙伴使用~...
kubernetes高级实战
一、模拟企业环境进行一个实战部署 [rootmaster node]# kubectl apply -f pod-tomcat.yaml pod/tomcat-test created [rootmaster node]# kubectl get pods NAME READY STATUS RESTARTS AGE tomcat-test 2/2 Running 0 2s [rootmaster node]…...