当前位置: 首页 > news >正文

Linux高级--2.4.2 linux TCP 系列操作函数 -- 深层理解

一、操作函数简介

在 Linux 中,TCP(传输控制协议)操作涉及多种系统调用和函数,通常用来创建套接字、连接、发送/接收数据、关闭连接等。以下是一些常用的 TCP 操作函数和它们的简要说明:

1. socket()

  • 函数原型: int socket(int domain, int type, int protocol);
  • 功能: 创建一个新的套接字(socket),它是与网络通信相关的基本对象。
  • 参数:
    • domain: 协议族(如 AF_INET 用于 IPv4,AF_INET6 用于 IPv6)。
    • type: 套接字类型(如 SOCK_STREAM 表示 TCP,SOCK_DGRAM 表示 UDP)。
    • protocol: 使用的协议,通常设为 0,由系统自动选择合适的协议。
  • 返回值: 返回一个套接字描述符(文件描述符),失败时返回 -1

2. bind()

  • 函数原型: int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • 功能: 将套接字与本地地址(IP 地址和端口)绑定。
  • 参数:
    • sockfd: 要绑定的套接字。
    • addr: 地址结构,通常是 struct sockaddr_in,指定 IP 和端口。
    • addrlen: 地址结构的长度。
  • 返回值: 成功返回 0,失败返回 -1

3. listen()

  • 函数原型: int listen(int sockfd, int backlog);
  • 功能: 将套接字设置为被动模式,等待客户端连接。
  • 参数:
    • sockfd: 套接字描述符。
    • backlog: 最多可连接的等待队列的大小。
  • 返回值: 成功返回 0,失败返回 -1

4. accept()

  • 函数原型: int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
  • 功能: 接受来自客户端的连接请求,并返回一个新的套接字描述符用于与客户端通信。
  • 参数:
    • sockfd: 已经调用 listen() 的套接字。
    • addr: 客户端的地址信息。
    • addrlen: 地址结构的大小。
  • 返回值: 返回新的套接字描述符,用于与客户端的通信,失败时返回 -1

5. connect()

  • 函数原型: int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • 功能: 客户端发起与服务器的连接请求。
  • 参数:
    • sockfd: 客户端套接字描述符。
    • addr: 目标服务器的地址信息。
    • addrlen: 地址结构的长度。
  • 返回值: 成功返回 0,失败返回 -1

6. send()

  • 函数原型: ssize_t send(int sockfd, const void *buf, size_t len, int flags);
  • 功能: 通过套接字发送数据。
  • 参数:
    • sockfd: 套接字描述符。
    • buf: 数据缓冲区。
    • len: 发送数据的长度。
    • flags: 发送标志(一般设为 0)。
  • 返回值: 返回实际发送的字节数,失败时返回 -1

7. recv()

  • 函数原型: ssize_t recv(int sockfd, void *buf, size_t len, int flags);
  • 功能: 从套接字接收数据。
  • 参数:
    • sockfd: 套接字描述符。
    • buf: 存储接收到数据的缓冲区。
    • len: 接收数据的最大长度。
    • flags: 接收标志(一般设为 0)。
  • 返回值: 返回实际接收的字节数,失败时返回 -1

8. close()

  • 函数原型: int close(int fd);
  • 功能: 关闭套接字,释放相关资源。
  • 参数:
    • fd: 套接字描述符。
  • 返回值: 成功返回 0,失败返回 -1

9. shutdown()

  • 函数原型: int shutdown(int sockfd, int how);
  • 功能: 用于关闭套接字的读、写或者双向通信。
  • 参数:
    • sockfd: 套接字描述符。
    • how: 控制关闭的方式,常用值为:
      • SHUT_RD: 关闭读取(不能再读取数据)。
      • SHUT_WR: 关闭写入(不能再发送数据)。
      • SHUT_RDWR: 同时关闭读写。
  • 返回值: 成功返回 0,失败返回 -1

10. getsockopt() 和 setsockopt()

  • 函数原型:
    • int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);
    • int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
  • 功能: 用于获取或设置套接字的选项(如 TCP 的各种参数,如缓冲区大小、超时时间等)。
  • 参数:
    • sockfd: 套接字描述符。
    • level: 设置选项的协议层级,通常为 SOL_SOCKET(套接字层)或 IPPROTO_TCP(TCP 层)。
    • optname: 选项名称(如 SO_RCVBUFSO_RCVBUF 等)。
    • optval: 选项的值。
    • optlen: 选项值的长度。
  • 返回值: 成功返回 0,失败返回 -1

11. select() 和 poll()

  • 函数原型:
    • int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
    • int poll(struct pollfd *fds, nfds_t nfds, int timeout);
  • 功能: 允许程序监听多个套接字,并在某些事件(如可读、可写等)发生时进行处理。

12. accept4()(Linux 特有)

  • 函数原型: int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags);
  • 功能: 与 accept() 类似,但支持额外的标志(如 SOCK_NONBLOCK 等),在非阻塞模式下返回。
  • 返回值: 返回一个新的套接字描述符,失败时返回 -1

小结:

这些是常见的用于 TCP 通信的 Linux 系统调用和函数。它们允许应用程序通过网络进行基本的连接管理、数据发送/接收等操作。通常情况下,服务器会使用 socket()bind()listen()accept() 来创建并处理客户端连接,而客户端则使用 socket()connect() 发起连接。数据的发送和接收使用 send()recv()

二、socket/listen/accept与TCB的关系

下面将详细解释在socket()listen()accept()等函数调用过程中,TCP控制块(TCB,struct tcp_sock)的创建和队列的使用,以及它们与文件描述符(socket_fdclient_fd)的关系。

1. socket() 函数调用后的TCB关联

  • 当你调用socket()函数时,操作系统会为这个套接字创建一个struct sock结构体(具体来说,如果是TCP套接字,将创建一个struct tcp_sock,它是struct sock的子类)。这个结构体就是TCP控制块(TCB),负责管理该套接字的所有TCP连接状态。
  • 创建的sock结构体会与socket_fd绑定,socket_fd是应用层与内核层进行通信的文件描述符。通过socket_fd,内核可以找到与之关联的sock结构体。

2. listen() 函数调用后的队列创建

  • 当调用listen()函数时,TCP进入监听状态,这时在与该监听套接字对应的TCB上会创建两个队列:
    • 半连接队列(Syn Queue):存放正在进行三次握手的连接。
    • 全连接队列(Accept Queue):存放已经完成三次握手的连接。

这些队列用于管理TCP连接的不同状态,但队列中的成员并不是直接的TCB(struct tcp_sock)类型

  • 半连接队列中的成员:是struct request_sock类型。request_sock是一个轻量级的数据结构,用于在三次握手未完成时存储连接请求的状态信息。在接收到客户端的SYN之后,服务端在半连接队列中分配一个request_sock,并等待三次握手完成。

  • 全连接队列中的成员:在三次握手完成后,内核会从半连接队列移除request_sock并创建一个完整的struct tcp_sock(也称作TCB),然后将其移入全连接队列中,表示该连接已经建立。

3. accept() 函数调用后

  • 当应用程序调用accept()函数时,内核会从全连接队列中取出一个已经完成三次握手的TCP连接。

  • 在全连接队列中的成员是一个完整的struct tcp_sock(即TCB),它记录了该连接的所有TCP状态。

  • 内核会为这个新的TCP连接创建一个新的文件描述符,称为client_fd,并将该文件描述符与这个TCP连接的TCB(struct tcp_sock)进行绑定。

    换句话说,client_fd与新连接的struct tcp_sock关联起来,使得通过client_fd可以操作该TCP连接(如发送或接收数据)。

总结流程

  1. socket(): 创建一个struct sock(具体为struct tcp_sock),并与socket_fd关联。

  2. listen(): 在tcp_sock上创建半连接队列和全连接队列:

    • 半连接队列存放struct request_sock,用于管理三次握手中的连接。
    • 全连接队列存放已建立连接的struct tcp_sock
  3. accept(): 从全连接队列中取出一个struct tcp_sock,为它分配一个新的文件描述符client_fd,并将client_fd与这个TCP连接的TCB(struct tcp_sock)绑定。

因此,调用accept()后,全连接队列中的TCP连接会与新的client_fd关联,应用程序通过client_fd来处理这个TCP连接。


三、listen函数backlog的作用

listen()函数的backlog参数在TCP服务器中用于指定全连接队列(Accept Queue)的最大长度,即允许在服务器上排队等待accept()的已建立连接的最大数量

1. listen() 函数及 backlog 参数的作用

当你调用listen()函数时,服务器的套接字进入监听状态,开始等待客户端的连接请求。backlog参数定义了以下内容:

  • 最大已完成连接数backlog参数指定全连接队列的最大长度,即已经完成三次握手但尚未被应用程序accept()取走的连接数。
  • 当客户端发起连接请求并完成了三次握手,连接会被放入全连接队列。如果队列已满,新完成的连接将被拒绝,客户端会收到TCP RST(复位)信号,表示连接无法建立。

2. backlog 参数的工作机制

listen(sockfd, backlog)中:
  • 全连接队列(Accept Queue) 存放的是已经完成三次握手、处于ESTABLISHED状态的连接,这些连接等待应用程序调用accept()来处理。
  • 半连接队列(Syn Queue) 管理尚未完全建立的连接(正在三次握手中的连接),它与backlog关系较小,主要受tcp_max_syn_backlog内核参数的影响。
具体行为:
  • 当全连接队列中的连接数达到backlog限制时,新完成的连接将无法进入队列,导致客户端收到RST包,连接被拒绝。
  • 如果设置的backlog值太小,服务器可能无法处理高并发连接,导致连接请求频繁被拒绝。
  • 如果设置的backlog值过大,可能会增加系统负担,尤其是在没有足够的资源或处理能力时。

3. backlog 参数的实际值

  • 虽然应用程序可以指定backlog的大小,但内核实际上会对该值进行限制。

  • Linux内核中有一个参数somaxconn,它定义了允许的最大backlog值。如果你在listen()中传入的backlog值大于/proc/sys/net/core/somaxconn中设定的值,系统会将backlog限制为somaxconn的值。

    • 查看和调整 somaxconn 参数
      cat /proc/sys/net/core/somaxconn
      echo 1024 > /proc/sys/net/core/somaxconn
      

4. 实际例子

假设你调用了如下的listen()函数:

listen(sockfd, 10);
  • 这意味着全连接队列的长度最大为10,即最多允许10个已经完成三次握手的连接排队等待accept()
  • 如果第11个连接尝试建立,服务器将返回TCP RST包,拒绝该连接。

5. 总结

  • backlog参数用于指定服务器上全连接队列的最大长度,即等待应用层accept()调用的已建立连接数的最大值
  • 过小的backlog值会导致高并发时连接被拒绝,而过大的值会增加系统资源占用,需根据系统处理能力合理设置。

四、半连接队列的限制

在 TCP 服务器中,半连接队列的数量(即 SYN 队列)由内核的 tcp_max_syn_backlog 参数控制。

1. 半连接队列(SYN队列):

  • 当客户端向服务器发送 SYN 请求时,服务器将这个连接请求放入 半连接队列(也称为 SYN 队列)。此队列用于存储尚未完成三次握手的连接。
  • 一旦握手完成并且服务器准备好接受数据,连接就会移入 全连接队列(Accept Queue)。

2. tcp_max_syn_backlog 参数:

  • 作用: 控制半连接队列的最大长度,即可以缓存的未完成三次握手的连接数。
  • 默认值: 在大多数 Linux 系统中,默认值通常为 128,意味着最多可以缓存 128 个尚未完成三次握手的连接。
  • 调整: 可以通过修改 /proc/sys/net/ipv4/tcp_max_syn_backlog 文件来调整此值。例如:
    echo 2048 > /proc/sys/net/ipv4/tcp_max_syn_backlog
    
    或者在 sysctl.conf 中添加:
    net.ipv4.tcp_max_syn_backlog=2048
    

3. SYN 队列溢出:

  • 如果半连接队列已满并且有新的 SYN 请求到达,内核会丢弃这些连接请求,通常客户端会收到一个 TCP RST(重置) 消息,或者如果客户端重试,可能会延迟连接。
  • 为了避免此情况,通常需要根据实际的网络负载来调整该参数,尤其是在高并发的服务器上。

4. 全连接队列:

  • 在调用 listen() 函数时,backlog 参数设置的是 全连接队列 的大小,即已完成三次握手的连接的最大数量。它并不直接影响半连接队列的大小。
  • 如果 全连接队列 已满,accept() 会阻塞,直到队列中有空间为止。

总结:

  • 半连接队列(SYN 队列)的大小是由 tcp_max_syn_backlog 参数控制。
  • 全连接队列(Accept Queue)的大小是由 listen() 函数的 backlog 参数控制。

因此,半连接队列和全连接队列的长度由不同的参数控制,而服务器需要根据实际的负载情况合理配置这些参数,以确保高并发时的连接性能和稳定性。

五、send函数的第四个参数是什么作用

send()函数的第四个参数是**flags**,用于指定发送操作的行为。通过设置不同的标志,应用程序可以控制send()函数的具体行为。

send() 函数的原型

ssize_t send(int sockfd, const void *buf, size_t len, int flags);
  • sockfd:目标套接字的文件描述符。
  • buf:要发送的数据的缓冲区。
  • len:要发送的数据长度。
  • flags:控制发送行为的标志位(即第四个参数)。

常用的 flags

以下是一些常用的标志及其作用,它们可以组合使用(使用按位或操作符 |):

  1. MSG_DONTWAIT

    • 使send()成为非阻塞操作。如果套接字的发送缓冲区已满,send()不会等待缓冲区空闲,而是立即返回,返回值为-1,并设置errnoEAGAINEWOULDBLOCK
    • 适用于非阻塞套接字,也可以临时使阻塞套接字表现为非阻塞模式。
  2. MSG_OOB(Out-of-Band Data):

    • 发送紧急数据(带外数据),仅适用于TCP协议。紧急数据会优先于普通数据处理,但在实际应用中,带外数据的使用较少。
    • 常用于一些需要快速响应的特殊场景。
  3. MSG_NOSIGNAL

    • 如果向已断开的连接发送数据,通常会触发SIGPIPE信号,导致程序终止。使用该标志可以抑制SIGPIPE信号,防止程序崩溃。
    • 适用于需要处理网络中断且不希望信号干扰的场景。
  4. MSG_CONFIRM

    • 仅适用于基于某些协议(如UDP)的发送,表示希望确认对端的存在,通常用于实现链路层的邻居确认。
    • 仅用于某些低层协议的特定场景,在常规TCP/UDP应用中较少使用。
  5. MSG_DONTROUTE

    • 发送数据时,不查找路由表,直接将数据发送到与目标网络直接相连的接口。通常用于网络诊断和本地网络通信的场景。
    • 在大多数普通应用场景中很少使用。
  6. MSG_EOR(End of Record):

    • 仅用于某些基于记录的协议,表示本次send()调用发送的数据是一个逻辑记录的结束。
    • 对于常见的TCP或UDP通信,这个标志不常用。
  7. MSG_MORE

    • 表示应用程序还有更多的数据要发送。在某些协议(如TCP)中,使用该标志时,内核会暂时将数据保留在缓冲区中,而不是立即发送,以减少网络上的包数。
    • 适合分多次发送数据,但希望减少网络开销的场景。

示例:使用 MSG_DONTWAITMSG_NOSIGNAL

char message[] = "Hello, World!";
int result = send(sockfd, message, sizeof(message), MSG_DONTWAIT | MSG_NOSIGNAL);if (result == -1) {if (errno == EAGAIN || errno == EWOULDBLOCK) {// 缓冲区已满,发送失败printf("Send would block, try again later.\n");} else {// 处理其他错误perror("send");}
}

总结

send()函数的第四个参数flags用于控制发送操作的行为。常见的标志包括MSG_DONTWAIT(非阻塞发送)、MSG_OOB(发送紧急数据)、MSG_NOSIGNAL(避免SIGPIPE信号)等。你可以根据具体应用场景使用不同的标志来改变send()的默认行为。


六、为什么握手要三次,挥手要四次,挥手中间的两次不能像握手那样合并在一起吗?

在TCP协议的三次握手四次挥手过程中,虽然在三次握手时可以将SYNACK合并到一个数据包发送,但在四次挥手过程中,FINACK通常不能合并到同一个数据包发送。这主要与TCP的连接状态和双方通信的半关闭状态有关。

1. 三次握手(SYN 和 ACK 合并的原因)

在三次握手中,通信双方需要同步序列号,建立可靠的连接。具体过程是:

  • 第一次握手:客户端发送一个SYN包,表示请求建立连接,并传递初始序列号。
  • 第二次握手:服务器收到SYN后,回复一个包含SYNACK的包。这里的ACK是对客户端SYN的确认,而SYN则是服务器请求建立连接的信号。因为SYNACK是针对不同的动作(SYN是服务器发起的,而ACK是对客户端请求的确认),可以一起合并发送。
  • 第三次握手:客户端收到后,发送ACK确认,连接建立。

这里之所以可以合并,是因为双方的状态在逻辑上是同步的,服务器既要发出自己的SYN,又要确认客户端的SYN,可以一起处理。

2. 四次挥手(ACK 和 FIN 通常不能合并的原因)

四次挥手过程用于关闭TCP连接,具体如下:

  • 第一次挥手:客户端发送一个FIN包,表示它要关闭连接(数据传输结束)。
  • 第二次挥手:服务器收到后,回复一个ACK,表示收到了客户端的FIN请求,但服务器可能还在发送数据。
  • 第三次挥手:服务器发送完数据后,再发送一个FIN包,表示它也同意关闭连接。
  • 第四次挥手:客户端收到服务器的FIN后,发送一个ACK包,确认关闭。
原因:
  1. 连接的半关闭状态: 在四次挥手过程中,TCP协议允许连接进入半关闭状态,即:

    • 当客户端发送FIN请求时,意味着客户端已经不再发送数据,但服务器还可以继续发送未完成的数据。
    • 客户端发送的FIN和服务器接收的ACK是两个不同的操作,它们代表了不同的状态。

    在这个阶段,服务器回复的ACK只是表明收到了客户端的FIN,但服务器还没有准备好关闭连接,因为可能仍然有数据需要发送。如果此时合并ACKFIN,就意味着服务器已经准备好关闭连接了,但实际上它可能还没有完成数据发送。

  2. 不同的时间点ACKFIN通常不会在同一时刻发生:

    • 客户端发FIN后,服务器需要立即回复一个ACK,但是服务器可能还在发送数据,并未准备好关闭连接。
    • 只有当服务器确认所有数据发送完毕后,它才会发送FIN来关闭连接。这两个操作通常在不同的时间点发生,无法合并。
  3. 确保数据完整性: 在四次挥手中,分开ACKFIN的发送有助于确保所有数据都能成功传输完毕。服务器通过先发送ACK确认收到客户端的关闭请求,并在数据发送完毕后才发送FIN,可以避免数据丢失或中途终止传输。

3. 总结

  • 在三次握手中,SYNACK可以合并到一个数据包中发送,因为它们在逻辑上是并行的操作,且是在同一时刻发送的。
  • 在四次挥手中,ACKFIN不能合并发送,因为它们通常发生在不同的时间点,表示不同的状态转换。ACK是对接收方收到FIN的确认,而FIN是表示发送方准备完全关闭连接,这两者之间可能存在数据传输的延迟,因此分开发送有助于确保传输的可靠性和完整性。
4. close/shutdown与挥手报文的关系:

        当recv函数返回0时表示收到了对方的FIN报文,此时close()调用后,会直接发出ACK + FIN。

但是用shutdown(sockfd, SHUT_RD)后只会发出 ACK,不会给发出FIN,还可以接着给对方发送数据。

七、shutdown函数 与 FIN 报文

是的,调用shutdown()函数时,根据调用参数,TCP连接可以发送FIN报文,但这取决于shutdown()的具体使用方式。

1. shutdown()函数的作用

shutdown()函数用于部分或完全关闭一个已经建立的TCP连接。它不同于close()函数,close()不仅会关闭连接,还会释放文件描述符,而shutdown()允许程序在不关闭文件描述符的情况下关闭连接的某一方向(发送或接收)。

shutdown()函数的原型:
int shutdown(int sockfd, int how);

其中:

  • sockfd:要关闭的套接字描述符。
  • how:决定关闭连接的方式。其值可以是以下之一:
    • SHUT_RD (0):关闭接收方向,该套接字不再能接收数据。
    • SHUT_WR (1):关闭发送方向,该套接字不再能发送数据,并发送FIN包。
    • SHUT_RDWR (2):同时关闭发送和接收方向,等同于分别调用SHUT_RDSHUT_WR

2. FIN报文的发送

shutdown()函数的how参数为SHUT_WRSHUT_RDWR时,TCP协议会发送一个FIN报文,告诉对方主机发送方已经关闭,数据发送已完成,表明不会再有更多的数据从该端发送。

详细说明:
  • SHUT_WR (1):关闭发送方向。当调用shutdown(sockfd, SHUT_WR)时,TCP协议栈会发送一个FIN报文,表示发送端不再发送数据。之后,这一端仍然可以接收对方的数据,但不能再发送任何数据。

  • SHUT_RDWR (2):同时关闭发送和接收方向。调用shutdown(sockfd, SHUT_RDWR)时,发送FIN,且无法再接收对方的数据。此时,连接相当于完全关闭,但文件描述符不会被释放,应用程序仍然可以继续使用文件描述符做其他操作。

3. shutdown()close()的区别

  • shutdown()函数可以只关闭连接的一部分(如只关闭发送而保留接收),而close()会完全关闭连接并释放套接字文件描述符。
  • 在调用close()时,如果还有数据没有发送完,TCP协议栈会继续尝试发送剩余数据,并最终发送FIN报文,完成四次挥手流程。

4. 典型使用场景

  • shutdown(sockfd, SHUT_WR):当一个应用程序完成了发送数据,但仍然希望接收对方的数据时,通常会调用这个函数。例如,HTTP协议中,服务器发送响应数据后可能会调用shutdown()来关闭发送方向,但仍然保留接收方向以读取客户端的请求。

  • shutdown(sockfd, SHUT_RDWR):用于完全关闭连接,类似于close(),但不释放文件描述符。

5. 总结

当调用shutdown(sockfd, SHUT_WR)shutdown(sockfd, SHUT_RDWR)时,TCP会发送FIN报文,表示发送方已经完成数据传输,关闭了发送方向。


八、bind函数端口号的设置

端口号在网络协议中起着非常重要的作用,它们被用来标识不同的服务或应用程序。端口号可以分为两大类:知名端口(Well-Known Ports)和动态或私有端口(Dynamic or Private Ports)。这些端口号由 Internet Assigned Numbers Authority (IANA) 管理,确保网络中的每个服务都能有唯一的端口标识。

端口号的分类

  • 知名端口(Well-Known Ports): 范围为 0 到 1023,通常分配给操作系统和知名的服务协议。
  • 注册端口(Registered Ports): 范围为 1024 到 49151,供用户和应用程序使用。
  • 动态或私有端口(Dynamic or Private Ports): 范围为 49152 到 65535,通常用于临时分配给客户端应用。

知名端口(0 - 1023)

这些端口通常由 IANA 分配给常用服务和协议,以下是一些常见的协议和对应的端口号:

端口号协议 / 服务说明
20FTP 数据传输(File Transfer Protocol)用于 FTP 数据传输
21FTP 控制(File Transfer Protocol)用于 FTP 控制连接
22SSH(Secure Shell)用于安全远程登录
23Telnet用于非加密的远程登录
25SMTP(Simple Mail Transfer Protocol)用于邮件传输
53DNS(Domain Name System)用于域名解析
67DHCP 服务器端(Dynamic Host Configuration Protocol)用于 DHCP 服务器
68DHCP 客户端(Dynamic Host Configuration Protocol)用于 DHCP 客户端
69TFTP(Trivial File Transfer Protocol)用于轻量级的文件传输
80HTTP(HyperText Transfer Protocol)用于 Web 服务(网页浏览)
110POP3(Post Office Protocol version 3)用于邮件接收
119NNTP(Network News Transfer Protocol)用于新闻组协议
123NTP(Network Time Protocol)用于网络时间同步
143IMAP(Internet Message Access Protocol)用于邮件接收(替代 POP3)
161SNMP(Simple Network Management Protocol)用于网络设备管理
194IRC(Internet Relay Chat)用于即时聊天
443HTTPS(HyperText Transfer Protocol Secure)用于加密的 Web 服务(HTTPS)
514Syslog用于网络设备和操作系统的日志记录
520RIP(Routing Information Protocol)用于路由协议
3389RDP(Remote Desktop Protocol)用于远程桌面访问

注册端口(1024 - 49151)

这些端口主要由软件供应商和开发者为其应用程序所使用。IANA 对这些端口进行注册,但它们通常不属于标准化的、固定的协议。以下是一些常见的服务和对应的端口号:

端口号协议 / 服务说明
1080SOCKS(SOCKS Proxy Protocol)用于代理服务
1433Microsoft SQL Server用于 Microsoft SQL 数据库服务
3306MySQL用于 MySQL 数据库服务
3389Microsoft RDP用于远程桌面协议
5432PostgreSQL用于 PostgreSQL 数据库服务
5900VNC(Virtual Network Computing)用于虚拟网络计算(远程桌面控制)
8080HTTP(Alternative Port)用于 Web 服务的备用端口(HTTP)
8888HTTP(Alternative Port)用于 Web 服务的备用端口(HTTP)

动态或私有端口(49152 - 65535)

这些端口通常由操作系统或应用程序动态分配给客户端程序使用,尤其是在进行临时连接时。它们不固定分配给任何特定服务。通常在 TCP/IP 会话中,客户端通过使用这些端口号连接到远程服务器的服务端口。

端口号范围说明
49152 - 65535动态端口范围,用于临时分配给客户端

端口号的使用说明

  1. 给用户的端口号:这些端口号由操作系统和服务程序为用户提供,用来执行应用程序或服务的访问。这些端口号一般需要符合特定协议,使用时需要确保没有冲突。

    • 例如:Web 服务使用 80 或 443 端口,邮件服务使用 25、110 或 143 端口。
  2. 给协议的端口号:协议端口号由 IANA(Internet Assigned Numbers Authority)分配,用于区分不同的网络协议和服务。许多常见的协议和服务有固定的端口号,比如 HTTP(80)、FTP(21)、SSH(22)等。

  3. 特定协议的端口号:许多协议和应用程序会规定固定的端口号,用于指定特定的服务。例如:

    • HTTP/HTTPS 协议默认使用端口 80 和 443。
    • FTP 使用端口 21 进行控制连接,端口 20 用于数据连接。
    • SMTP 使用端口 25 发送邮件,POP3 使用端口 110 接收邮件。
  4. 动态分配端口:客户端与服务器建立连接时,通常会使用动态端口(范围 49152 到 65535)。例如,在 HTTP 请求中,客户端使用随机分配的端口号连接服务器的端口 80 或 443。

端口号的重要性

  • 网络服务和协议标识:端口号帮助操作系统区分不同的网络协议和服务,使得同一台机器可以同时提供多个不同的服务。
  • 安全性考虑:某些服务使用的端口号可能存在安全漏洞,因此安全防护设备(如防火墙)通常会对端口号进行过滤,阻止不安全的端口。
  • 端口扫描:攻击者通常通过端口扫描来查找开放的端口和运行的服务,进而寻找潜在的攻击入口。

总结

  • 端口号是网络通信中的重要组成部分,允许不同的服务和应用程序在同一台机器上并行运行。
  • 端口号分为知名端口、注册端口和动态端口,分别用于系统服务、应用程序服务和临时连接。
  • 各种协议和服务使用不同的端口号,IANA 负责管理这些端口号的分配。

九、TCP系统调用函数的 -- 阻塞性

在 TCP 编程中,某些网络操作可能会阻塞,即函数在没有完成操作之前会等待特定条件的发生。这些函数通常用于执行需要等待数据到达、连接建立、或者连接关闭等操作的任务。阻塞行为通常与网络状态、系统资源、以及协议本身的特性相关。

以下是一些常见的会阻塞的 TCP 相关函数,以及它们为什么会阻塞:

1. accept()

  • 阻塞原因: accept() 用于在服务器端接受一个已经完成三次握手的连接请求。如果没有等待的连接,它会阻塞,直到有客户端发起连接请求。
  • 何时阻塞: 当没有客户端连接请求到达时,accept() 会阻塞,直到有连接请求到来。
  • 代码示例:
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(8080);bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
    listen(sockfd, 5);int client_sock = accept(sockfd, NULL, NULL);  // 阻塞直到有连接到来
    if (client_sock == -1) {perror("accept");
    }
    

2. recv() / recvfrom() / read()

  • 阻塞原因: 这些函数用于从套接字中接收数据。如果没有数据可读,它们会阻塞,直到有数据可用。recv() 在默认情况下会阻塞,直到接收到至少一个字节的数据。
  • 何时阻塞: 如果缓冲区中没有数据(例如,客户端没有发送数据),则会阻塞等待数据的到来。
  • 代码示例:
    char buffer[1024];
    int bytes_received = recv(client_sock, buffer, sizeof(buffer), 0);  // 阻塞直到数据到达
    if (bytes_received == -1) {perror("recv");
    }
    

3. send() / sendto() / write()

  • 阻塞原因: 如果发送缓冲区已满,send()write() 可能会阻塞,直到发送缓冲区有足够的空间来存储数据。特别是在网络拥堵或者接收方的速度跟不上发送速度时,发送函数可能会阻塞。
  • 何时阻塞: 当套接字处于阻塞模式且发送缓冲区已满时,send()write() 会阻塞,直到缓冲区有空间。
  • 代码示例:
    const char *msg = "Hello, Client!";
    int bytes_sent = send(client_sock, msg, strlen(msg), 0);  // 阻塞直到数据被发送
    if (bytes_sent == -1) {perror("send");
    }
    

4. connect()

  • 阻塞原因: connect() 用于客户端与服务器建立 TCP 连接。如果服务器没有响应或不可达,connect() 会阻塞,直到连接成功建立或者超时。
  • 何时阻塞: 如果没有可用的远程服务器响应或服务器未准备好接收连接,connect() 会阻塞,直到连接成功或失败。
  • 代码示例:
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(8080);
    server_addr.sin_addr.s_addr = inet_addr("192.168.1.100");int result = connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));  // 阻塞直到连接成功
    if (result == -1) {perror("connect");
    }
    

5. listen()

  • 阻塞原因: listen() 是在 TCP 服务器端调用的,用于将套接字设为监听模式,等待客户端的连接请求。它本身不会阻塞,但会准备好接收连接。在后续调用 accept() 时,才会阻塞。
  • 何时阻塞: listen() 本身不会阻塞,但它为 accept() 阻塞操作做好准备。
  • 代码示例:
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(8080);bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
    listen(sockfd, 5);  // 为后续的accept准备
    

6. shutdown()

  • 阻塞原因: shutdown() 可以关闭套接字的某些操作(如读、写),并等待数据的完全传输或清理。如果你调用 shutdown() 来关闭写操作,它可能会阻塞,直到 TCP 将所有待发送的数据发送完毕。
  • 何时阻塞: 如果套接字有未发送的数据需要传输,shutdown() 会阻塞,直到数据传输完毕。
  • 代码示例:
    int result = shutdown(sockfd, SHUT_WR);  // 关闭写端,阻塞直到所有数据被发送
    if (result == -1) {perror("shutdown");
    }
    

为什么阻塞?

TCP 是一种面向连接、可靠的数据传输协议,它保证数据的可靠交付,确保所有数据包按照顺序到达目的地,并通过流量控制、拥塞控制等机制避免网络过载。为确保这些特性,某些操作需要等待特定事件的发生,导致阻塞:

  1. 等待数据到达:如在调用 recv() 时,系统必须等待数据从远程主机传输到本地。
  2. 等待连接建立:如在 accept()connect() 中,系统必须等待对方准备好接收或发起连接。
  3. 缓冲区未满:如在发送数据时,如果发送缓冲区已满,系统会等待缓冲区腾出空间来进行数据传输。

如何避免阻塞?

  1. 非阻塞模式:可以将套接字设置为非阻塞模式,在这种模式下,调用函数不会阻塞。如果操作无法立即完成,它会返回 EAGAINEWOULDBLOCK 错误,应用程序可以做其他事情或稍后再试。

    • 代码示例
      int flags = fcntl(sockfd, F_GETFL, 0);
      fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);  // 设置套接字为非阻塞模式
      
  2. 超时设置:对于 connect()recv() 等函数,可以设置超时时间,避免长时间阻塞。比如可以使用 select()poll() 来实现超时检测。

  3. 多线程或异步 I/O:在多线程程序中,阻塞的操作可以放在单独的线程中执行,主线程继续进行其他任务。使用异步 I/O 也是一种避免阻塞的方式,特别是在高性能网络应用中。

总结

TCP 编程中,许多函数会阻塞,尤其是与连接、数据接收和发送相关的操作。accept()recv()send()connect() 等函数在没有数据或连接不可用时会阻塞,直到特定条件满足。为了避免阻塞,开发者可以使用非阻塞模式、超时机制或多线程来处理阻塞操作。

十、调用返回失败的情况分析

在 TCP 编程中,许多常用的函数会返回失败的情况,尤其是在网络条件不理想或系统资源不足时。了解每个函数返回失败时的具体错误原因非常重要,这有助于调试和错误处理。以下是对常见的 TCP 函数返回失败时的错误情况的详细说明:

1. accept()

accept() 用于接受客户端连接。当调用失败时,返回值为 -1,并设置 errno 以指示具体的错误原因。

  • EINVAL: 如果套接字未正确绑定(如 bind() 未调用)或者套接字类型不支持 accept()(例如,UDP 套接字),则返回此错误。
  • ECONNABORTED: 如果先前的连接被中止,accept() 返回此错误。
  • EFAULT: 传递给 accept() 的地址指针无效。
  • EINTR: 系统调用被信号中断。accept() 被中断时返回该错误。

2. recv() / recvfrom() / read()

这些函数用于从 TCP 套接字接收数据。当返回 -1 时,表示出现错误,errno 将设置为相应的错误代码。0时表示对方已经断开连接。

  • EAGAINEWOULDBLOCK: 套接字被设置为非阻塞模式,且没有数据可用时返回该错误。
  • EBADF: 套接字无效,可能是已经关闭或未正确初始化。
  • EINTR: 系统调用被信号中断。操作在信号处理程序执行后被中断,导致 recv() 返回失败。
  • ENOTCONN: 套接字未连接,调用 recv() 时,TCP 套接字未完成连接。
  • ECONNRESET: 对方主机强制关闭连接,TCP 连接被重置,导致接收操作失败。
  • ENOTSOCK: 目标文件描述符不是一个套接字。
  • EFAULT: 提供的缓冲区地址无效。

3. send() / sendto() / write()

这些函数用于向 TCP 套接字发送数据,失败时返回 -1,并设置 errno

  • EAGAINEWOULDBLOCK: 套接字被设置为非阻塞模式,且发送缓冲区已满,无法继续发送数据。
  • EBADF: 套接字无效,可能是已经关闭或未正确初始化。
  • EINTR: 系统调用被信号中断,导致 send() 被中断。
  • ENOTCONN: 套接字未连接时调用 send() 会失败。
  • ECONNRESET: 对方主机强制关闭连接,导致连接重置,发送操作失败。
  • ENOTSOCK: 目标文件描述符不是一个套接字。
  • EPIPE: 当发送数据到一个已经关闭的连接时返回此错误,表示对方已经关闭了连接,写入操作失败。

4. connect()

connect() 用于客户端建立与服务器的连接。如果返回值是 -1,则表示连接失败,errno 会被设置为特定错误值。

  • ECONNREFUSED: 目标服务器拒绝连接。通常是目标服务器未启动或未监听指定的端口。
  • ETIMEDOUT: 连接请求超时。在指定时间内没有完成连接。
  • EINPROGRESS: 如果套接字是非阻塞模式且连接正在进行中,这个错误会发生。不是错误,表示连接正在进行。
  • EAGAIN: 套接字设置为非阻塞模式时,连接尝试会立即返回 EAGAIN 错误,表示无法立即连接。
  • EADDRINUSE: 本地地址已在使用中,无法为新连接分配。
  • ENETUNREACH: 网络不可达,可能是由于路由或网络配置问题。
  • EHOSTUNREACH: 主机不可达,通常由于目标主机未开机或网络不可达。
  • ENOTSOCK: 目标文件描述符不是一个套接字。

5. listen()

listen() 用于在服务器端启动监听。失败时返回 -1,并设置 errno

  • EADDRINUSE: 如果指定的端口已被其他应用程序占用,listen() 会失败并返回此错误。
  • EINVAL: 如果套接字不是流式套接字(例如 UDP 套接字),则会发生此错误。
  • ENOTSOCK: 传入的文件描述符不是套接字。

6. shutdown()

shutdown() 用于关闭套接字的读写操作。如果返回 -1,则表示操作失败,errno 被设置为错误值。

  • EBADF: 套接字无效,可能是已经关闭或者未正确初始化。
  • EINTR: 系统调用被信号中断,shutdown() 被中断。
  • ENOTSOCK: 目标文件描述符不是一个套接字。

7. fcntl()

fcntl() 用于获取或设置套接字的属性,如设置非阻塞模式等。如果返回 -1,表示操作失败,errno 被设置为错误码。

  • EBADF: 套接字无效,可能是已经关闭或未正确初始化。
  • EINVAL: 无效的命令或参数。
  • ENOTTY: 非法的文件描述符类型,不支持该操作。

8. bind()

bind() 用于将套接字与本地地址(IP 和端口)绑定。如果返回 -1,表示绑定失败,errno 被设置为特定错误码。

  • EADDRINUSE: 地址已被使用,无法绑定。
  • EADDRNOTAVAIL: 本地地址不可用,可能由于没有该网络接口或地址配置问题。
  • EBADF: 套接字无效。
  • EINVAL: 无效的套接字类型,通常是由于套接字类型和协议不匹配。

总结

了解这些 TCP 函数返回失败时的错误原因非常重要,有助于调试和错误处理。一般情况下,当函数返回 -1 时,errno 会提供失败的详细信息。开发者应该根据不同的错误代码进行适当的错误处理,例如通过重试、记录日志、关闭套接字等方式来恢复网络操作,确保程序的健壮性。

十一、recv返回0时的详细说明

在 TCP 编程中,recv() 函数的返回值为 0 是一个非常重要的情况,它表示 对方关闭了连接。这个情况常常被用来判断连接是否已经正常关闭。

  • recv() 返回 0:
    • 当调用 recv() 时,如果返回值是 0,这并不表示错误,而是表示连接已经被对方关闭(也就是对方发送了一个 TCP FIN 包 来终止连接),并且没有更多的数据可接收。
    • 这个返回值表示对方已经优雅地关闭了连接,并且没有数据需要读取。

具体情况:

  1. TCP 连接正常关闭

    • 在正常的 TCP 连接关闭过程中,通信双方会经过四次挥手(Four-way Handshake),具体来说:
      • 一方(通常是主动关闭的那方)发送一个 FIN 包,表示希望关闭连接。
      • 接收方确认收到 FIN 包,并发送一个 ACK 包
      • 接收方也会发送自己的 FIN 包,表示自己也准备关闭连接。
      • 主动关闭的一方确认收到接收方的 FIN 包,完成连接关闭过程。

    在这个过程中,当 recv() 读取到接收到的 FIN 包 后,表示对方已经关闭了连接,函数返回 0

  2. recv() 返回 0 的例子: 下面是一个简单的代码示例,演示如何使用 recv() 判断对方关闭连接:

    char buffer[1024];
    int bytes_received;// 假设客户端已经连接到服务器
    bytes_received = recv(client_sock, buffer, sizeof(buffer), 0);if (bytes_received == 0) {printf("The remote side has closed the connection gracefully.\n");// 对方关闭了连接,进行相应的清理工作close(client_sock);
    } else if (bytes_received < 0) {perror("recv failed");
    } else {// 处理接收到的数据printf("Received %d bytes: %s\n", bytes_received, buffer);
    }
    

    在上面的代码中:

    • 如果 recv() 返回 0,表示对方已经正常关闭了连接。此时,通常需要关闭自己的套接字并清理相关资源。
    • 如果 recv() 返回负值(< 0),表示发生了错误,可以通过 errno 获取错误原因。

其他返回情况:

  • 返回负值(< 0

    • 如果 recv() 返回一个负值,通常表示发生了错误。常见的错误包括:
      • EINTR: 系统调用被信号中断。
      • EAGAINEWOULDBLOCK: 套接字处于非阻塞模式,且没有数据可读取。
      • ECONNRESET: 连接被对方重置(例如,远程主机强制关闭了连接)。
  • 返回大于零的正数

    • 如果返回一个大于 0 的值,表示成功接收到数据,值表示接收到的数据字节数。开发者可以处理这些数据。

为什么 recv() 返回 0 代表对方关闭了连接?

这是因为在 TCP 协议中,连接关闭是通过发送 FIN 包来实现的。此时,连接的另一端会通知接收端自己已经没有数据发送,并且希望关闭连接。当接收端收到这个 FIN 包后,recv() 返回 0,表示没有更多的数据可读。

  • TCP FIN 包:当连接的某一方发送 FIN 包时,它表示已经发送完所有数据并且希望关闭连接。接收方接收到 FIN 包后,会回复一个 ACK 包,表示已经收到关闭请求。此时,接收方的接收缓冲区为空,不再有数据传输,recv() 将返回 0,表示对方已关闭连接。

总结:

  • recv() 返回 0 表示对方已经关闭了连接,通常是正常的连接关闭过程。
  • 该返回值是用于 优雅地关闭连接 的指示,表明没有更多数据可读,开发者可以清理资源并关闭自己的套接字。
  • 当遇到 0 时,通常需要进行关闭套接字、清理资源等操作。

0voice · GitHub

相关文章:

Linux高级--2.4.2 linux TCP 系列操作函数 -- 深层理解

一、操作函数简介 在 Linux 中&#xff0c;TCP&#xff08;传输控制协议&#xff09;操作涉及多种系统调用和函数&#xff0c;通常用来创建套接字、连接、发送/接收数据、关闭连接等。以下是一些常用的 TCP 操作函数和它们的简要说明&#xff1a; 1. socket() 函数原型: int…...

小程序租赁系统开发指南与实现策略

内容概要 在如今这个快节奏的时代&#xff0c;小程序租赁系统的开发正逐渐成为许多商家提升服务质量与效率的重要选择。在设计这样一个系统时&#xff0c;首先要明白它的核心目标&#xff1a;便捷、安全。用户希望在最短的时间内找到需要的物品&#xff0c;而商家则希望通过这…...

威胁建模助力企业“建防御 抓运营”

本文为安全知识图谱技术白皮书《践行安全知识图谱&#xff0c;携手迈进认知智能》精华解读系列第六篇——威胁建模技术&#xff0c;重点介绍基于知识图谱的威胁建模应用。 如何做好威胁建模 如今&#xff0c;随着技术的变化&#xff0c;攻防技术不对等和攻防双方关注面不同&a…...

soular使用教程

用 soular 配置你的组织&#xff0c;工作更高效&#xff01;以下是快速上手的简单步骤&#xff1a; &#xfeff; 1. 账号管理 可以对账号信息进行多方面管理&#xff0c;包括分配不同的部门、用户组等&#xff0c;从而确保账号权限和职责的清晰分配。 &#xfeff; 1.1 用…...

WPF编程excel表格操作

WPF编程excel表格操作 摘要NPOI安装封装代码测试代码 摘要 Excel操作几种方式 使用开源库NPOI(常用&#xff0c;操作丰富)使用Microsoft.Office.Interop.Excel COM组件(兼容性问题)使用OpenXml(效率高)使用OleDb(过时) NPOI安装 封装代码 using System; using System.IO; u…...

银河麒麟操作系统安装达梦数据库(超详细)

目录 引言1. 前期准备1.1 安装麒麟系统1.2 下载达梦数据库安装包&#xff08;DM8&#xff09;1.3 上传安装包到麒麟系统1.4 挂载安装包&#xff08;iso&#xff09;文件1.5 配置安装用户和组1.6 创建安装路径及修改权限1.7 设置临时安装目录 2. 安装达梦数据库&#xff08;DM8&…...

SpringCloudAlibaba实战入门之路由网关Gateway初体验(十一)

Spring Cloud 原先整合 Zuul 作为网关组件,Zuul 由 Netflix 公司提供的,现在已经不维护了。后面 Netflix 公司又出来了一个 Zuul2.0 网关,但由于一直没有发布稳定版本,所以 Spring Cloud 等不及了就自己推出一个网关,已经不打算整合 zuul2.0 了。 一、什么是网关 1、顾明…...

struct sock

struct sock是套接口在网络层的表示,它包含了套接字在网络通信中的各种状态和参数。以下是对struct sock的详细解析: 定义与位置 struct sock通常在内核源代码的某个头文件中定义,例如include/net/sock.h。它是网络通信中非常重要的数据结构,用于在内核中表示一个套接字。…...

77、将adaface的mtcnn模型npy文件转成atlas310p模型,并进行推理

基本思想:将adaface的mtcnn模型npy文件转成atlas310p模型进行推理。同时比对结果 ubuntu@ubuntu:~$ git clone https://github.com/mk-minchul/AdaFace.git Cloning into AdaFace... remote: Enumerating objects: 236, done. remote: Counting objects: 100% (109/109), don…...

Docker应用-项目部署及DockerCompose

文章目录 Docker应用-项目部署1. 项目部署-后端1.1 修改配置1.2 项目打包1.3 编写Dockerfile1.4 创建镜像1.5 创建并运行容器1.6 测试 2. 项目部署-前端2.1 html前端静态目录2.2 nginx.config编写2.3 部署宿主机服务器2.4 创建容器并挂载2.5 测试 3. DockerCompose3.1 基本语法…...

Java重要面试名词整理(十一):网络编程

文章目录 概念网络协议计算机网络是什么&#xff1f;定义和分类计算机网络发展简史 计算机网络体系结构OSI七层模型TCP/IP模型TCP/IP协议族IP、TCP和UDPARPTCP/IP网络传输中的数据地址和端口号**端口号的确定** TCP特性TCP三次握手TCP四次挥手&#xff08;分手&#xff09; UDP…...

html + css 淘宝网实战

之前有小伙伴说&#xff0c;淘宝那么牛逼你会写代码&#xff0c;能帮我做一个一样的淘宝网站吗&#xff0c;好呀&#xff0c;看我接下来如何给你做一个淘宝首页。hahh,开个玩笑。。。学习而已。 在进行html css编写之前 先了解下网页的组成和网页元素的尺寸吧 1.网页的组成 …...

Linux打包压缩解压 --- 打包tar命令(归档)

一、tar命令打包&#xff08;归档&#xff09; 在 Linux 中&#xff0c;tar 是一种用于归档文件的工具。通过此命令可将多个文件或目录组合成单个档案文件&#xff0c;可以搭配gzip和bzip等压缩命令让文件体积更小&#xff0c;在配置服务器前备份服务器现有配置&#xff0c;会…...

流架构的读书笔记(2)

流架构的读书笔记&#xff08;2&#xff09; 一、建模工具之一沃德利地图 推测技术的发展,交流和辩论思想的最有力的方法是沃德利地图 沃德利地图的制作步骤 1确定范围和用户需求 2确定满足用户需求所需的组件 3在一条范围从全新到被人们接受的演进轴上评估这些组成 部分的演…...

Xshell远程连接提示“找不到匹配的host key算法“问题处理

1.问题描述 Xshell连接远程服务器node1&#xff0c;提示找不到匹配的host key算法&#xff1b;但是用同机房的其他服务器可以使用ssh连接到这个node1机器&#xff1b; 2.问题处理 问题处理尝试了很多方法&#xff0c;可能大家遇到的有所不同&#xff0c;可以尝试一下本文中的…...

Qt C++关于QSpinBox、QDoubleSpinBox的输入框内鼠标点击事件无法触发截取信号的解决办法

项目场景&#xff1a; 基于Qt C 开发鼠标点击spinbox的触发任务时&#xff0c;我基于QSpinBox继承开发了一个新类&#xff0c;用于弹出自定义键盘。 问题描述 在鼠标点击spinbox的边框以及上下键的时候&#xff0c;能够触发覆写的mousePressEvent&#xff0c;但是一旦鼠标点击…...

【ES6复习笔记】Symbol 类型及其应用(9)

一、Symbol 简介 Symbol 是 JavaScript 中的一种基本数据类型&#xff0c;它表示唯一的标识符。Symbol 的主要目的是防止属性名冲突&#xff0c;尤其是在多个代码库或模块中共享对象时。Symbol 值可以用作对象的属性名&#xff0c;这样可以确保属性名是唯一的&#xff0c;不会…...

深度学习笔记(4)——视频理解

视频理解 视频理解的问题:视频太大了 解决方案:在切片上训练,低FPS,低分辨率 测试的时候:在不同的clips上运行模型,取平均预测结果 视频由图片序列组成: 单帧CNN模型 训练普通的2D CNN模型,对每一帧进行分类&#xff0c;通常是视频分类的一个非常强的基线方法。 Late Fusio…...

Flink定时器

flink的定时器都是基于事件时间&#xff08;event time&#xff09;或事件处理时间&#xff08;processing time&#xff09;的变化来触发响应的。对一部分新手玩家来说&#xff0c;可能不清楚事件时间和事件处理时间的区别。我这里先说一下我的理解&#xff0c;防止下面懵逼。…...

springboot餐厅点餐系统丨源码+数据库+万字文档+PPT

作者简介&#xff1a; 作者&#xff1a;学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等 文末获取“源码数据库万字文档PPT”&#xff0c;支持远程部署调试、运行安装。 技术框架 开发语言&#xff1a;Java 框架&#xff1a;springbo…...

记一个itertools排列组合和列表随机排序的例子

朋友不知道哪里弄来了一长串单词列表&#xff0c;一定要搞个单词不重复的组合。那么这个时候我们就可以想到读书时所学的排列组合知识了&#xff0c;而这个在Python中可以怎么实现呢&#xff1f;我记录如下&#xff1a; 使用itertools模块实现排列组合 在 Python 中&#xff…...

Intent--组件通信

组件通信1 获取子活动的返回值 创建Activity时实现自动注册&#xff01;【Activity必须要注册才能使用】 默认 LinearLayout 布局&#xff0c;注意 xml 中约束布局的使用&#xff1b; 若需要更改 线性布局 只需要将标签更改为 LinearLayout 即可&#xff0c;记得 设置线性布局…...

数据分析与应用:如何分析7日动销率和滞销率?

目录 0 需求描述 1 数据准备 1.1 订单明细表 1.2 商品信息表 2 SQL实现 3 问题分析与总结...

信息系统管理工程第8章思维导图

软考信管第8章的思维导图也实在是太长了&#xff0c;制作的耗时远超过之前的预计。给你看看思维导图的全貌如下&#xff0c;看看你能够在手机上滚动多少个屏幕 当你看到这段文字的时候&#xff0c;证明你把思维导图从上到下看完了&#xff0c;的确很长吧&#xff0c;第8章的教程…...

5-pandas常用操作2

前言 一、df.max() 计算每列最大值 二、df.apply() 1.可以传函数 代码如下&#xff08;示例&#xff09;&#xff1a; # lambda 匿名函数自定义 f lambda x:x.max()-x.min() # x参数 冒号后是返回值 df.apply(f) # 默认axis0,所以这里是按列求最大值-最小值2.可以直…...

【HarmonyOS之旅】ArkTS语法(一)

目录 1 -> 基本UI描述 1.1 -> 基本概念 1.2 -> UI描述规范 1.2.1 -> 无参数构造配置 1.2.2 -> 必选参数构造配置 1.2.3 -> 属性配置 1.2.4 -> 事件配置 1.2.5 -> 子组件配置 2 -> 状态管理 2.1 -> 基本概念 2.2 -> 页面级变量的状…...

基于Spring Boot + Vue3实现的在线商品竞拍管理系统源码+文档

前言 基于Spring Boot Vue3实现的在线商品竞拍管理系统是一种现代化的前后端分离架构的应用程序&#xff0c;它结合了Java后端框架Spring Boot和JavaScript前端框架Vue.js的最新版本&#xff08;Vue 3&#xff09;。该系统允许用户在线参与商品竞拍&#xff0c;并提供管理后台…...

解决k8s部署dashboard时一直处于Pending状态的问题

直接用离线包就行 命令 [rootk8s-master ~]# docker load -i calico-image-v3.25.0.tar [rootk8s-master ~]# kubectl apply -f calico.yaml链接在https://download.csdn.net/download/weixin_42759398/90192045 [rootk8s-master ~]# docker load -i calico-image-v3.25.0.t…...

【新方法】通过清华镜像源加速 PyTorch GPU 2.5安装及 CUDA 版本选择指南

下面详细介绍所提到的两条命令&#xff0c;它们的作用及如何在你的 Python 环境中加速 PyTorch 等库的安装。 1. 设置清华镜像源 pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple这条命令的作用是将 pip &#xff08;Python 的包管理工具&#xf…...

Excel批量设置行高,Excel表格设置自动换行后打印显示不全,Excel表格设置最合适的行高后打印显示不全,完美解决方案!!!

文章目录 说个问题&#xff08;很严重&#xff01;&#xff01;&#xff01;&#xff09;写个方案会Python看这里Python环境搭建不存在多行合并存在多行合并 不会Python看这里 说个问题&#xff08;很严重&#xff01;&#xff01;&#xff01;&#xff09; 平时处理Excel表格…...

高阶数据结构之并查

并查集的概念 之前我们曾学过树&#xff0c;二叉树、二叉搜索树、红黑树、AVL树等&#xff0c;而并查集可以看做是这些树的集合&#xff0c;也就是森林&#xff0c;它也是一种树型结构&#xff0c;不过是顺序的树型结构&#xff0c;如果有学过堆的同学应该会很熟悉。 它的作用是…...

Pandas04

Pandas01 Pandas02 Pandas03 文章目录 内容回顾1 数据的合并和变形1.1 df.append (了解)1.2 pd.concat1.3 merge 连接 类似于SQL的join1.4 join (了解) 2 变形2.1 转置2.2 透视表 3 MatPlotLib数据可视化3.1 MatPlotLib API 套路 &为什么要可视化3.2 单变量可视化3.3 双变量…...

ECMAScript 标准解析及应用

摘要&#xff1a; 本文深入解析了 ECMAScript 标准&#xff0c;包括其发展历程、核心语法、数据类型、对象模型、函数特性等方面。详细阐述了如何在实际的 Web 开发和 JavaScript 编程中应用这些特性&#xff0c;通过具体的代码示例展示了 ECMAScript 标准在构建高效、健壮的应…...

2025最新版Java面试八股文大全

一、Java并发面试题 1、 ThreadLocal 1.1 谈谈你对ThreadLocal的理解&#xff1f; ThreadLocal的作用主要是做数据隔离&#xff0c;填充的数据只属于当前线程&#xff0c;变量的数据对别的线程而言是相对隔离的。它不是针对程序的全局变量&#xff0c;只是针对当前线程的全局…...

从零开始学AI,完成AI 企业知识库的AI问答搭建

1&#xff1a;本地安装一个ollama玩下&#xff0c;ollama下载模型默认路径为C盘&#xff0c;但该盘空间不足。 解决方案&#xff1a;添加系统环境变量OLLAMA_MODELS&#xff0c;设置其值为新的路径。 2&#xff1a;安装完成后&#xff0c;访问http://127.0.0.1:11434/ 查看服务…...

路过石岩浪心古村

周末常去的七彩城堡儿童乐园附近经常有老房子&#xff0c;没想到老房子最多的地方还是浪心古村。而且越看越有历史。 见到一座写着《序西书室》的房子&#xff0c;我最开始以为是一个古代的学校。但是查了百度更加不知道什么意思了哈。‌“序西书室”‌是指《文心雕龙》中的一个…...

【Leecode】Leecode刷题之路第93天之复原IP地址

题目出处 93-复原IP地址-题目描述 题目描述 个人解法 思路&#xff1a; todo代码示例&#xff1a;&#xff08;Java&#xff09; todo复杂度分析 todo官方解法 93-复原IP地址-官方解法 方法1&#xff1a;回溯 思路&#xff1a; 代码示例&#xff1a;&#xff08;Java&…...

121. 买卖股票的最佳时机

题目链接&#xff1a;https://leetcode.cn/problems/best-time-to-buy-and-sell-stock/description/?envTypestudy-plan-v2&envIdtop-100-liked 算法思路&#xff1a; 虽然已经提示我们使用贪心算法了&#xff0c;但是我最开始的时候却不知道怎么使用&#xff0c;因为如果…...

Python Polars快速入门指南:LazyFrames

前文已经介绍了Polars的Dataframe, Contexts 和 Expressions&#xff0c;本文继续介绍Polars的惰性API。惰性API是该库最强大的功能之一&#xff0c;使用惰性API可以设定一系列操作&#xff0c;而无需立即运行它们。相反&#xff0c;这些操作被保存为计算图&#xff0c;只在必要…...

OpenCV-Python实战(10)——形态学

1、腐蚀 cv2.erode() 可以删除图像中的噪音点。 可以删除毛边。 分割图像&#xff08;当图像连接的不够紧密时&#xff09; 。 img cv2.erode(src*,kernel*,anchor*,iterations*,borderType*,borderValue*)img&#xff1a;目标图像。 src&#xff1a;原始图像。 kernel&…...

在Windows上读写Linux磁盘镜像的一种方法

背景 嵌入式开发中&#xff0c;经常会把系统的Linux磁盘镜像保存到Windows上&#xff0c;以便上传到网盘备份或发送给工厂&#xff0c;但是如果想读取/修改镜像中的某个文件&#xff0c;一般有2种方案&#xff1a; 直接访问 就是用虚拟磁盘软件将镜像文件挂载成磁盘&#xf…...

基于STM32F103控制L298N驱动两相四线步进电机

文章目录 前言一、模块参数二、接口说明三、准备工作四、直流电机驱动引脚接线效果展示 五、两相四线步进电机驱动步进电机相关概念拍数驱动时序引脚接线效果展示 六、参考示例 前言 L298N 是一种常见的双 H 桥电机驱动模块&#xff0c;广泛用于驱动直流电机和步进电机。它基于…...

Blazor开发中注册功能设计研究

Blazor开发中注册功能设计是为了用户可以高效、安全地完成注册并登录系统。以高效和用户友好为目标,结合校验、注册和登录功能,为用户提供一个完整的账户管理流程,同时保障系统安全性和稳定性。注册页面应该结构清晰、布局合理,既满足基本注册功能,又通过响应式设计与视觉…...

Docker安装体验kuboard-k8s多集群管理工具

文章目录 1.kuboard是什么&#xff1f;2.docker安装命令2.1 Linux上docker环境安装命令2.2 Windows上docker环境安装命令 3.登录访问3.1首页访问地址3.2 默认账号密码3.3 登录页3.4 首页 4总结 1.kuboard是什么&#xff1f; 参看官网: https://kuboard.cn/gitHub项目地址&…...

组建基于IPV6的网络

现在很多单位使用IPV6的网络&#xff0c;地址资源紧张的状况得到了缓解&#xff0c;很多单位目前采用双栈运行&#xff0c;就是网络设备上同时跑IPV4和IPV6。 IPV6的网络与IPV4网络的配置与IPV4基本相同&#xff0c;注意地址规则与格式的不同。 长度&#xff1a;     IPv6地…...

浙江肿瘤医院病理库存储及NAS共享存储(磁盘阵列)方案-Infortrend普安科技

Infortrend金牌代理-燊通智联信息科技发展&#xff08;上海&#xff09;有限公司与院方多轮沟通&#xff0c;详细讨论性能与容量要求&#xff0c;最终决定采用GSe统一存储设备&#xff0c;与现有病理系统服务器无缝对接&#xff0c;每台设备配1.92T SSD作缓存加速原数据读写&am…...

UE5在蓝图中使用VarestX插件访问API

在Fab中安装好VarestX免费插件 这个插件可以用来远程请求http和api等&#xff0c;返回json等格式内容 插件网址 https://www.fab.com/zh-cn/listings/d283e40c-4ee5-4e73-8110-cc7253cbeaab 虚幻里开启插件 然后网上随便搜个免费api测试一下&#xff0c;这里我找了个微博热搜…...

QML学习(五) 做出第一个简单的应用程序

通过前面四篇对QML已经有了基本的了解&#xff0c;今天先尝试做出第一个单页面的桌面应用程序。 1.首先打开Qt,创建项目&#xff0c;选择“QtQuick Application - Empty” 空工程。 2.设置项目名称和项目代码存储路径 3.这里要注意选择你的编译器类型&#xff0c;以及输出的程…...

Java日志框架:log4j、log4j2、logback

文章目录 配置文件相关1. properties测试 2. XMl使用Dom4j解析XML Log4j与Log4j2日志门面 一、Log4j1.1 Logges1.2 Appenders1.3 Layouts1.4 使用1.5 配置文件详解1.5.1 配置根目录1.5.2 配置日志信息输出目的地Appender1.5.3 输出格式设置 二、Log4j22.1 XML配置文件解析2.2 使…...

tcp 的重传,流量控制,拥塞控制

tcp 的重传解决了什么问题tcp的几种重传机制分别解决什么问题?方案 1: 超时重传方案2: 快速重传选择性确认(sack)d-sack(重复接收) 滑动窗口:累计应答 流量控制解决什么问题?如何做的?问题1: 那如果第一次发送的数据都大于缓冲区的大小怎么办?问题2: 如果剩余大小为0会发生…...