linux系统编程-----下

这篇具有很好参考价值的文章主要介绍了linux系统编程-----下。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

linux网络编程

tcp通信

Berkeley Socket

TCP/IP协议族标准只规定了网络各个层次的设计和规范,具体实现则需要由各个操作系统厂商完成。最出名的网络库由BSD 4.2版本最先推出,所以称作伯克利套接字,这些API随后被移植到各大操作系统中,并成为了网络编程的事实标准。 socket 即套接字是指网络中一种用来建立连接、网络通信的设备,用户创建了 socket 之后,可以通过其发起或者接受 TCP 连接、可以向 TCP 的发送和接收缓冲区当中读写TCP数据段,或者发送 UDP 文本。

地址信息设置

**struct sockaddr 和 struct sockaddr_in
**
我们主要以IPv4为例介绍网络的地址结构。主要涉及的结构体有 struct in_addr 、 struct sockaddr 、 struct sockaddr_in 。其中 struct sockaddr 是一种通用的地址结构,它可以描述一个 IPv4或者IPv6的结构,所有涉及到地址的接口都使用了该类型的参数,但是过于通用的结果是直接用它 来描述一个具体的IP地址和端口号十分困难。

  struct sockaddr_in {
               sa_family_t    sin_family; /* address family: AF_INET */
               in_port_t      sin_port;   /* port in network byte order */
               struct in_addr sin_addr;   /* internet address */
           };

 /* Internet address. */
  struct in_addr {
               uint32_t       s_addr;     /* address in network byte order */
           };

大小端(Endianness :是指多个字节的数据在内存中的存储方式。在计算机系统中,一个多字节的数据类型会被分为若干个字节来存储,而这些字节的存放顺序就称为大小端。

大端法(Big-endian):是指数据的高位字节存储在内存的低地址处,而数据的低位字节存储在内存的高地址处。例如,在十六进制表示下,整数0x12345678在内存中的存储顺序为0x12 0x34 0x56 0x78。这种存储方式通常用于网络协议和一些处理器架构中,如Motorola 68000和IBM PowerPC等。

小端法(Little-endian):则是指数据的低位字节存储在内存的低地址处,而数据的高位字节存储在内存的高地址处。例如,在十六进制表示下,整数0x12345678在内存中的存储顺序为0x78 0x56 0x34 0x12。这种存储方式通常用于微处理器和操作系统中,如x86架构。

对于不同大小端的计算机之间进行数据交换时,需要进行大小端转换。具体来说,将一个多字节的数据类型拆分成单个字节后,按照相反的顺序重新组合即可完成大小端转换。

在C语言中,可以使用以下两个函数进行大小端转换操作:

  • htons()和htonl()函数:这两个函数可将16位或32位无符号整数从主机字节序转换为网络字节序,其中htons()用于转换16位整数,htonl()用于转换32位整数。如果本机字节序和网络字节序相同,则不会进行任何转换操作。

  • ntohs()和ntohl()函数:这两个函数可将16位或32位无符号整数从网络字节序转换为主机字节序,其中ntohs()用于转换16位整数,ntohl()用于转换32位整数。如果本机字节序和网络字节序相同,则不会进行任何转换操作。

需要注意的是,以上四个函数都需要包含头文件<arpa/inet.h>。此外,在其他编程语言中也有类似的函数可供使用。

域名和ip地址的对应关系

域名(Domain Name)和IP地址(Internet Protocol Address)之间存在一种对应关系,即每个域名都对应着一个或多个IP地址。

这种对应关系由DNS(Domain Name System)服务器来维护。当我们在浏览器中输入一个域名时,浏览器会向本地DNS服务器发送查询请求,请求该域名对应的IP地址。如果本地DNS服务器缓存了这个域名和其对应的IP地址,则直接返回该IP地址;否则,本地DNS服务器会向根DNS服务器发送查询请求,根DNS服务器会返回一个指向该域名所属顶级域名的权威DNS服务器的地址。接下来,本地DNS服务器再向该权威DNS服务器发送查询请求,获取该域名对应的IP地址,并将其缓存起来。最后,本地DNS服务器将该IP地址返回给浏览器,浏览器通过该IP地址访问目标网站。

举例来说,假设我们要访问网站www.example.com。首先,浏览器会向本地DNS服务器发送查询请求,请求该域名对应的IP地址。如果本地DNS服务器没有该域名的缓存记录,它会依次向根DNS服务器、com顶级域名的权威DNS服务器以及example.com域名的权威DNS服务器发送查询请求,最终获取到www.example.com对应的IP地址,并将其缓存起来。之后,本地DNS服务器将该IP地址返回给浏览器,浏览器通过该IP地址访问目标网站。

需要注意的是,一个域名可以对应多个IP地址,这些IP地址通常是为了实现负载均衡、故障转移等功能而提供的。此外,在特定情况下,一个IP地址也可以对应多个域名,例如,多个虚拟主机共用一台服务器的情况。

相关函数

#include <netdb.h>
struct hostent *gethostbyname(const char *name);
struct hostent {
char *h_name; /* official name of host */
char **h_aliases; /* alias list */
int h_addrtype; /* host address type */
int h_length; /* length of address */
char **h_addr_list; /* list of addresses */
}

TCP通信

linux系统编程-----下

socket

Socket是一种在应用层和传输层之间的接口,可以用于实现不同机器或同一机器上的进程间通信。它是TCP/IP协议族中最基本的网络编程接口之一。

在Socket编程中,一个Socket通常由IP地址和端口号组成,用于标识网络上的一个进程。在客户端程序中,可以创建一个Socket并连接到服务器指定的IP地址和端口号上,从而与该服务器进行通信;在服务器程序中,可以创建一个Socket并绑定到指定的IP地址和端口号上,从而监听客户端连接请求并与其建立连接,以进行通信。

Socket可以使用不同的传输协议,如TCP(Transmission Control Protocol)和UDP(User Datagram Protocol),以实现可靠传输或非可靠传输。对于TCP协议,Socket提供面向连接的服务,数据传输之前需要先建立连接;对于UDP协议,Socket提供无连接的服务,数据传输时不需要事先建立连接。

Socket编程接口通常包含以下几个基本函数:socket()、bind()、listen()、accept()、connect()和send()/recv()等。其中,socket()用于创建Socket;bind()用于将Socket绑定到指定的IP地址和端口号上;listen()用于监听客户端连接请求;accept()用于接受客户端连接请求并建立连接;connect()用于建立与服务器的连接;send()/recv()用于发送和接收数据。

一般根据选择TCP或者UDP有着固定的写法。 socket 函数的返回值是一个非负整数

bind

bind()函数是一种可以在C语言中使用的方法,它可以用来创建一个新的函数,并将指定的this值和参数绑定到新的函数中。当新的函数被调用时,它会自动将这些绑定的值作为参数传递给原始函数。

connet

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

listen函数

listen()是一个网络编程中的函数,用于在服务器上等待客户端连接。当一个客户端请求与服务器建立连接时,服务器使用listen()函数开始监听传入的连接请求。一旦有连接请求到达,它们就被放置在一个队列中,直到服务器准备好接受这些连接并将它们分配给可用的线程或进程。

int listen(int sockfd, int backlog);

其中,sockfd 是套接字描述符,backlog 是等待连接队列的最大长度。

调用 listen 函数后,该套接字变成了被动套接字,可以接受来自客户端的连接请求。backlog 参数指定了等待连接队列的最大长度,如果有新的连接请求到达而等待队列已满,则客户端会收到拒绝连接的错误信息。

一般来说,backlog 的值应该设置为系统能够支持的最大值,以确保能够处理所有可能的连接请求。在 Linux 系统上,可以通过 cat /proc/sys/net/core/somaxconn 命令查看系统支持的最大队列长度,也可以使用 sysctl 命令来修改该值。

accept函数

accept() 是一个网络编程中的函数,用于接受客户端连接并返回与客户端通信的新 socket 对象和客户端地址。在服务器脚本中,我们使用 listen() 函数开始监听传入的连接请求,当有新的客户端连接请求到达时,accept() 函数会被调用以接受该连接。

accept 函数由服务端调用,用于从全连接队列中取出下一个已经完成的TCP连接。如果全连接队列为 空,那么 accept 会陷入阻塞。一旦全连接队列中到来新的连接,此时 accept 操作就会就绪,这种就绪 是读操作就绪,所以可以使用 select 函数的读集合进行监听。当 accept 执行完了之后,内核会创建一 个新的套接字文件对象,该文件对象关联的文件描述符是 accept 的返回值,文件对象当中最重要的结 构是一个发送缓冲区和接收缓冲区,可以用于服务端通过TCP连接发送和接收TCP段。

区分两个套接字是非常重要的。通过把旧的管理连接队列的套接字称作监听套接字,而新的用于发送和 接收TCP段的套接字称作已连接套接字。通常来说,监听套接字会一直存在,负责建立各个不同的TCP连 接(只要源IP、源端口、目的IP、目的端口四元组任意一个字段有区别,就是一个新的TCP连接),而某 一条单独的TCP连接则是由其对应的已连接套接字进行数据通信的。

#include <sys/types.h>
#include <sys/socket.h>

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

sockfd: 必须,表示服务器的 socket 描述符,也就是要监听的套接字。

addr: 可选,表示客户端的地址信息,如果需要获取客户端的地址信息,则需要将这个参数传递给 accept() 函数。

addrlen: 必须,表示客户端地址结构体的长度,在调用 accept() 函数之前必须初始化为客户端地址结构体的大小。

当 accept() 函数成功时,会返回一个新的连接套接字(也就是通信套接字),可以通过这个新的套接字来进行后续的数据传输和通讯。如果 accept() 函数失败,则返回 -1,并设置相应的错误码,可以使用 strerror() 函数来获取对应的错误描述信息。

recv函数

ssize_t recv(int sockfd, void *buf, size_t len, int flags);

其中,sockfd 是套接字描述符,buf 是一个指向缓冲区的指针,len 是缓冲区的最大长度(以字节为单位),flags 是操作标志位。

该函数返回接收到的字节数,如果出现错误,则返回 -1。可以通过 errno 全局变量获取详细的错误信息。

recv 函数会阻塞当前线程,直到有数据可读或者发生错误。如果在调用 recv 函数之前没有数据可读,那么它将一直阻塞,直到有数据到达为止。

buf 缓冲区用于存储接收到的数据,len 参数指定了缓冲区的大小,即最多能够接收到的数据量。如果实际接收到的数据超过了缓冲区大小,则多余的数据将被丢弃。

flags 参数可以用来指定一些操作标志位,比如是否启用 MSG_OOB(带外数据)模式、是否在接收时进行关闭操作等。

send函数

ssize_t send(int sockfd, const void *buf, size_t len, int flags);

其中,sockfd 是套接字描述符,buf 是指向要发送数据的缓冲区的指针,len 是要发送的数据的长度(以字节为单位),flags 是操作标志位。

该函数返回已经成功发送的字节数,如果出现错误,则返回 -1。可以通过 errno 全局变量获取详细的错误信息。

buf 缓冲区用于存储要发送的数据,len 参数指定了需要发送的数据的长度。注意,在发送前应该确保缓冲区中的数据已经准备好,并且长度不超过缓冲区的大小。

flags 参数可以用来指定一些操作标志位,比如是否启动 MSG_OOB(带外数据)模式、是否在发送时进行关闭操作等。

send和recv函数

send() 和 recv() 函数是在网络编程中用于发送和接收数据的两个核心函数。这两个函数都是基于套接字(socket)实现的,因此只能用于网络通信。

send() 函数的格式如下:

send(socket, buffer, size, flags)

其中,

  • socket:指定要发送数据的套接字;
  • buffer:指定要发送的数据缓冲区;
  • size:指定要发送的数据长度;
  • flags:指定发送数据时的选项。

send() 函数的返回值为实际发送的数据量,如果出现错误,则返回 -1。

recv() 函数的格式如下:

recv(socket, buffer, size, flags)

其中,

  • socket:指定要接收数据的套接字;
  • buffer:指定用于接收数据的缓冲区;
  • size:指定缓冲区的大小;
  • flags:指定接收数据时的选项。

recv() 函数的返回值为实际接收到的数据量,如果出现错误,则返回 -1。

dos攻击

DOS(Denial of Service),即拒绝服务攻击,是一种通过向目标服务器发送大量请求来耗尽其资源以使其无法正常响应的攻击方式。

DOS 攻击可分为两类:

  1. 消耗计算资源的攻击。该类攻击通常会向目标服务器发送大量的请求,比如 SYN 请求洪水攻击、Ping 洪水攻击等,使其花费大量 CPU 和内存资源处理这些请求而无法正常工作。

  2. 消耗网络带宽的攻击。该类攻击通常会向目标服务器发送大量的数据包,比如 UDP 洪水攻击、ICMP 洪水攻击等,以消耗网络带宽并将目标服务器的网络连接拥堵,使其无法正常响应。

防范 DOS 攻击的措施主要包括以下几点:

  • 增加硬件设备的负载能力,比如增加带宽和存储容量等。

  • 防火墙和入侵检测系统等安全设备的配置和使用。

  • 在服务器端进行限制性访问,比如限制对某些关键资源的访问等。

  • 使用专门的软件和工具来监测网络流量和识别异常活动,及时发现并隔离攻击行为。

  • 增加访问控制的机制,比如限制某些 IP 地址的访问、设置访问频率限制等。

总之,防范 DOS 攻击需要综合考虑硬件设备的能力、网络安全设备的配置和使用、服务器端的安全设置以及对网络流量的监测和管理。

TIME_WAIT和setsockopt

如果是服务端主动调用 close 断开的连接,即服务端是四次挥手的主动关闭方,由之前的TCP状态转换图可知,主动关闭方在最后会处于一个固定2MSL时长的TIME_WAIT等待时间。在此状态期间,如果尝试使用 bind 系统调用对重复的地址进行绑定操作,那么会报错。

如果是服务端主动调用 close 断开的连接,即服务端是四次挥手的主动关闭方,由之前的TCP状态转换 图可知,主动关闭方在最后会处于一个固定2MSL时长的TIME_WAIT等待时间。在此状态期间,如果尝 试使用 bind 系统调用对重复的地址进行绑定操作,那么会报错。

int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);

setsockopt()函数

setsockopt()函数是用于设置套接字选项的系统调用。该函数可以用来设置一系列不同的选项,例如设置套接字的发送或接收缓冲区的大小、开启或关闭Nagle算法、设定超时时间等。

int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);

UDP通信

linux系统编程-----下

sendto和recvfrom函数

sendto()recvfrom()`是Linux系统中用于进行UDP套接字通信的函数,它们分别用于发送数据和接收数据。下面是这两个函数的简要说明:

  1. sendto()

    函数原型为ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen)

    参数说明:

    • sockfd:需要发送数据的UDP套接字文件描述符。
    • buf:指向存放待发送数据的缓冲区。
    • len:待发送数据的长度。
    • flags:传输控制标志,一般设为0即可。
    • dest_addr:指向目的地址信息结构体的指针,包括目的IP地址和端口号等信息。
    • addrlen:指定dest_addr所指向的地址结构体的长度。

    返回值:

    • 成功:返回实际发送的字节数。
    • 失败:返回-1,并设置errno为相应的错误代码。
  2. recvfrom()

    函数原型为ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen)

    参数说明:

    • sockfd:需要接收数据的UDP套接字文件描述符。
    • buf:指向存放接收数据的缓冲区。
    • len:缓冲区的长度。
    • flags:传输控制标志,一般设为0即可。
    • src_addr:指向发送方地址信息结构体的指针,包括发送方IP地址和端口号等信息。
    • addrlen:指向src_addr所指向的地址结构体的长度。

    返回值:

    • 成功:返回实际接收到的字节数。
    • 失败:返回-1,并设置errno为相应的错误代码。

使用UDP协议进行通信时,sendto()recvfrom()函数是常用的数据发送和接收函数,它们可以通过指定目的地址和源地址来实现点对点的通信。同时也可以通过设置传输控制标志等参数来控制数据传输的行为。

这两个函数的行为类似于 send 和 recv

epoll系统调用

epoll的基本原理:

和 select 一样, epoll 也是一种IO多路复用机制,它可以监听多个设备的就绪状态,让进程或者线程 只在有事件发生之后再执行真正的读写操作。 epoll 可以在内核态空间当中维持两个数据结构:监听事 件集合和就绪事件队列。监听事件集合用来存储所有需要关注的设备(即文件描述符)和对应操作(比 如读、写、挂起和异常等等),当监听的设备有事件产生时,比如网卡上接收到了数据并传输到了缓冲 区当中时,硬件会采用中断等方式通知操作系统,操作系统会将就绪事件拷贝到就绪事件队列中,并且 找到阻塞在 epoll_wait 的线程,让其就绪。监听事件集合通常是一个红黑树,就绪事件队列是一个线 性表。

和 select 相比, epoll 的优势如下:
除了水平触发,还支持边缘触发。

  • 监听事件集合容量很大,有多少内存就能放下多少文件描述符。
  • 监听事件集合常驻内核态,调用 epoll_wait 函数不会修改监听性质,不需要每次将集合从用户态 拷贝到内核态。
  • 监听事件和就绪事件的状态分为两个数据结构存储,当 epoll_wait 就绪之后,用户可以直接遍历 就绪事件队列,而不需要在所有事件当中进行轮询。

有了这些优势之后, epoll 逐渐取代了 select 的市场地位,尤其是在管理巨
大量连接的高并发场景 中, epoll 的性能要远超 select 。

使用epoll取代select

使用 epoll 主要有这样几个函数:

  • epoll_create 用于在内核之中创建一个 epoll 文件对象,这个文件对象中就包含之前所描述的监听事件集合和就绪设备集合。 epoll_create 的参数目前已经没有意义,填写一个大于0的数值即可。 epoll_create 的返回值是该文件对象对应的文件描述符。
  • epoll_ctl 用于调整监听事件集合。 op 的选项是 EPOLL_CTL_ADD 、 EPOLL_CTL_MOD 和EPOLL_CTL_DEL ,分别表示添加、修改和删除事件, event->events 用于描述事件的类型,其中EPOLLIN 表示读,EPOLLOUT 表示写。可以通过命令 man 7 socket 查看每个操作对应的事件类型如何。
  • epoll_wait 用于使线程陷入阻塞,直到监听的设备就绪或者超时。events 是一个传入传出参数,用于存储就绪设备队列, epoll_wait 的返回值就是就绪设备队列的长度,即就绪设备的个数。 timeout 描述超时时间,单位是毫秒,-1是永久等待。 maxevent 传入一个足够大的正数即可

使用epoll关闭长期不发消息的连接

和 select 一样, epoll 也可以监听已连接队列,判断 accept 是否就绪。配合上超时机制,可以用来实现自动断开功能:超过一段时间未发送消息的客户端的TCP连接会被服务端主动关闭。

epoll的边缘触发

epoll_wait 的就绪触发有两种方式:一种是默认的水平触发方式(Level-triggered),另一种是边缘触发 模式(Edge-triggered)。以读事件为例子:水平触发模式下,只要缓冲区当中存在数据,就可以使 epoll_wait 就绪;在边缘触发的情况下,如果缓冲区中存在数据,但是数据一直没有增多,那么 epoll_wait 就不会就绪,只有缓冲区的数据增多的时候,即下图中绿色的上升沿部分时,才能使 epoll_wait 就绪。
linux系统编程-----下
使用水平触发的话,线程能够以更短的响应时间来处理事件,但是这可能会导致饥饿问题,如果存在某 个事件传输的数据量过大,那么线程就会多次就绪直到处理完所有数据为止,而一些其他的任务所占用 的资源就会相对变少。使用边缘触发可以避免这个问题,为了确保读操作可以将所有数据读完,可以考 虑使用循环配合非阻塞的形式来处理。

在线程池架构中,主线程通常会将实际的IO交给子线程即工作线程完成,采用边缘触发可以有效地降低 主线程的响应频率,提高整体的性能。除此以外,如果一次请求对应一次响应是用户追求的通信模式, 那么边缘触发正好符合。

进程池和线程池

进程池的实现

我们以一个文件下载的应用为例子来介绍进程池结构:客户端可以向服务端建立连接,随后将服务端中存储的文件通过网络传输发送到客户端,其中一个服务端可以同时处理多个客户端连接的,彼此之间互不干扰。

零拷贝、sendfile和splice

目前我们传输文件的时候是采用 read 和 send 来组合完成,这种当中的数据流向是怎么样的呢?首先打开一个普通文件,数据会从磁盘通过DMA设备传输到内存,即文件对象当中的内核缓冲区部分,然后调用 read 数据会从内核缓冲区拷贝到一个用户态的buf上面(buf是 read 函数的参数),接下来调用send ,就将数据拷贝到了网络发送缓存区,最终实现了文件传输。

但是实际上这里涉及了大量的不必要的拷贝操作,比如下图中 read 和 send 的过程:
linux系统编程-----下

如何减少从内核文件缓冲区到用户态空间的拷贝呢?解决方案就是使用 mmap 系统调用直接建立文件和用户态空间buf的映射。这样的话数据就减少了一次拷贝。在非常多的场景下都会使用 mmap 来减少拷贝次数,典型的就是使用图形的应用去操作显卡设备的显存。除此以外,这种传输方式也可以减少由于系统调用导致的CPU用户态和内核态的切换次数。

linux系统编程-----下
使用 mmap 系统调用只能减少数据从磁盘文件的文件对象到用户态空间的拷贝,但是依然无法避免从用户态到内核已连接套接字的拷贝(因为网络设备文件对象不支持 mmap )。 sendfile 系统调用可以解决这个问题,它可以使数据直接在内核中传递而不需要经过用户态空间,调用 sendfile 系统调用可以直接将磁盘文件的文件对象的数据直接传递给已连接套接字文件对象,从而直接发送到网卡设备之上(在内核的底层实现中,实际上是让内核磁盘文件缓冲区和网络缓冲区对应同一片物理内存)。

linux系统编程-----下

#include <sys/sendfile.h>
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);

使用 sendfile 的时候要特别注意, out_fd 一般只能填写网络套接字的描述符,表示写入的文件描述符, in_fd 一般是一个磁盘文件,表示读取的文件描述符。从上述的需求可以得知, sendfile 只能用于发送文件方的零拷贝实现,无法用于接收方,并且发送文件的大小上限是2GB。

考虑到 sendfile 只能将数据从磁盘文件发送到网络设备中,那么接收方如何在避免使用 mmap 的情况下使用零拷贝技术呢?

一种方式就是采用管道配合 splice 的做法。 splice 系统调用可以直接将数据从内核管道文件缓冲区发送到另一个内核文件缓冲区,也可以反之,将一个内核文件缓冲区的数据直接发送到内核管道缓冲区中。所以只需要在内核创建一个匿名管道,这个管道用于本进程中,在磁盘文件和网络文件之间无拷贝地传递数据。

ssize_t splice(int fd_in, loff_t *off_in, int fd_out,loff_t *off_out, size_t len, unsigned int flags);

linux系统编程-----下

进程池

进程池是一种在并发编程中常用的技术,它可以管理一个固定数量的进程,并且可以重复利用这些进程。通常情况下,在程序运行时,需要处理多个任务,但是如果使用传统的方式,每次都创建新的进程或线程来执行任务,会导致系统资源消耗过大,而且效率较低。因此,我们可以使用进程池来管理一组可复用的进程,从而提高系统的资源利用率和程序的执行效率。

使用进程池的好处是可以充分利用系统资源,提高程序的运行效率。同时,进程池也可以避免频繁地创建和销毁进程,减少系统负担,并且方便进行任务管理和监控。但是,由于进程池中的进程是有限的,所以在提交任务时需要考虑好进程数和任务量之间的平衡,避免出现进程数过多或者任务量过大的情况,从而导致系统资源的浪费。

线程池

线程池(Thread Pool)是一种线程管理机制,它可以在创建线程的成本和上下文切换开销之间寻求平衡。线程池会事先创建一定数量的线程并将它们保存在一个队列中,当需要执行任务时,就从队列中取出一个空闲的线程,并将任务交给它执行,当任务完成后,该线程不会被销毁而是继续留在线程池中等待下一次任务的到来。

使用线程池的好处主要有以下几点:

  1. 降低线程创建和销毁的开销:线程的创建和销毁都是比较耗费CPU资源的,而线程池可以减少这些开销。
  2. 提高程序的响应速度:线程池中的线程已经事先创建好了,等待任务的到来,因此可以提高程序的响应速度。
  3. 控制并发线程数:线程池可以限制并发线程的数量,避免过多的线程竞争导致系统崩溃。
  4. 支持任务排队:线程池可以将任务排队,保证每个任务都会得到处理,避免任务丢失或者阻塞。

总之,线程池是一种非常实用的技术,可以帮助我们更好地管理线程,提高程序的性能和稳定性。文章来源地址https://www.toymoban.com/news/detail-475888.html

到了这里,关于linux系统编程-----下的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Linux网络编程:socket & fork()多进程 实现clients/server通信

    UNIX网络编程:socket实现client/server通信 随笔简单介绍了TCP Server服务单客户端的socket通信,但是并未涉及多客户端通信。 对于网络编程肯定涉及到多客户端通信和并发编程 (指在同时有大量的客户链接到同一服务器),故本随笔补充这部分知识。 而且并发并发编程涉及到多进程

    2024年02月05日
    浏览(41)
  • Linux网络编程:Socket服务器和客户端实现双方通信

    目录 一,什么是网络编程 二,为什么使用端口号 三,TCP协议与UDP协议 ①TCP(传输控制协议) ②UDP(用户数据报协议,User Data Protocol) ③总结归纳 四,Socket服务器和客户端的开发流程 五,服务器和客户端相关API说明 ①socket()函数 ②bind()函数 ③listen()函数 ④accept()函数 ⑤客户端

    2024年02月11日
    浏览(65)
  • linux【网络编程】之HTTPS协议,一文了解HTTPS是如何保证通信安全的

    在上篇文章中我们了解到什么事HTTP协议,HTTP协议内容都是按照⽂本的⽅式明⽂传输的.这就导致在传输过程中出现⼀些被篡改的情况,本期我们来探讨一下HTTPS协议。 HTTPS( 超文本传输安全协议 )也是⼀个应⽤层协议.是在HTTP协议的基础上引⼊了⼀个加密层. HTTPS:默认端口与

    2024年02月08日
    浏览(55)
  • Linux网络编程:socket、客户端服务器端使用socket通信(TCP)

    socket(套接字),用于网络中不同主机间进程的通信。 socket是一个伪文件,包含读缓冲区、写缓冲区。 socket必须成对出现。 socket可以建立主机进程间的通信,但需要协议(IPV4、IPV6等)、port端口、IP地址。          (1)创建流式socket套接字。                 a)此s

    2024年02月11日
    浏览(57)
  • Linux网络编程:socket & pthread_create()多线程 实现clients/server通信

    UNIX网络编程:socket fork()多进程 实现clients/server通信 随笔介绍了通过fork()多进程实现了服务器与多客户端通信。但除了多进程能实现之外,多线程也是一种实现方式。 重要的是,多进程和多线程是涉及操作系统层次。随笔不仅要利用pthread_create()实现多线程编程,也要理解线

    2024年02月05日
    浏览(41)
  • Linux系统应用编程(五)Linux网络编程(上篇)

    1.两个网络模型和常见协议 (1)OSI七层模型(物数网传会表应) 物理层、数据链路层、网络层、传输层、会话层、表示层、应用层(自下到上) (2)TCP/IP四层模型(网网传应) 网络接口层(链路层)、网络层、传输层、应用层 (3)常见网络协议所属层 2.字节序 (1)两种

    2023年04月25日
    浏览(34)
  • linux【网络编程】TCP协议通信模拟实现、日志函数模拟、守护进程化、TCP协议通信流程、三次握手与四次挥手

    Tcp通信模拟实现与Udp通信模拟实现的区别不大,一个是面向字节流,一个是面向数据报;udp协议下拿到的数据可以直接发送,tcp协议下需要创建链接,用文件描述符完成数据的读写 1.1.1 接口认识 1.1.1.1 listen:监听socket 1.1.1.2 accept:获取连接 通信就用accept返回的文件描述符,

    2024年02月06日
    浏览(48)
  • 【深入浅出C#】章节 8: 网络编程和远程通信:网络编程和远程通信

    计算机网络是指连接多台计算机设备,通过通信链路共享资源和信息的系统。它构建了一个相互连接的世界,使得人们可以在不同地点进行数据交换和资源共享。网络编程是指在计算机网络中,使用编程语言进行通信和数据传输的技术。现代应用中,网络编程发挥着重要作用

    2024年02月12日
    浏览(55)
  • Java网络编程 - 网络编程介绍 - 网络通信三要素

    什么是网络编程 ? 网络编程可以让程序与网络上的其他设备中的程序进行数据交互。 网络编程基本模式 : 常见的通信模式有如下2种形式:Client-Server( CS: 客户端与服务器模式 ) 、 Browser/Server( BS: 浏览器与服务器模式 ) Client-Server(CS)模式 Browser/Server(BS)模式 实现网络编程关键的三

    2024年02月02日
    浏览(50)
  • Java 网络编程 —— 安全网络通信

    SSL(Secure Socket Layer,安全套接字层)是一种保证网络上的两个节点进行安全通信的协议。IETF(Interet Engineering Task Force)国际组织对 SSL 作了标准化,制定了 RFC2246 规范,并将其称为传输层安全(Transport Layer Security,TLS) SSL 和 TLS 都建立在 TCP/IP 的基础上,一些应用层协议,如

    2024年02月11日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包