云南网站建设哪家公司好厦门快速建网站

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

云南网站建设哪家公司好,厦门快速建网站,怎么让自己的网站通过域名访问不了,wordpress生成静态页一、epoll_wait和select对比

  1. 阻塞和非阻塞 在Linux C语言中进行socket编程时#xff0c;epoll_wait 和 select 都是用于多路I/O复用的系统调用#xff0c;但是它们的行为可以设置为阻塞和非阻塞模式#xff0c;这取决于调用它们时所使用的参数。 让我们分别看看 epoll…一、epoll_wait和select对比
  2. 阻塞和非阻塞 在Linux C语言中进行socket编程时epoll_wait 和 select 都是用于多路I/O复用的系统调用但是它们的行为可以设置为阻塞和非阻塞模式这取决于调用它们时所使用的参数。 让我们分别看看 epoll_wait 和 select epoll_wait epoll_wait 函数用于等待由 epoll 文件描述符指向的事件它可以工作在阻塞模式也可以工作在非阻塞模式。 int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout); 在这里timeout 参数决定 epoll_wait 的行为其值可以是    - -1 表示无限期阻塞直到有事件发生。    - 0 表示非阻塞调用即使没有事件也立即返回。 - 大于0的值表示等待指定毫秒数如果在这个时间段内没有事件发生它将返回。 select select 函数也是多路I/O复用的调用它监视一组文件描述符以查看是否有数据可读、可写或有异常。 int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); 其中timeout 参数同样控制 select 的行为可以设置为    - NULL 表示无限期阻塞直到有文件描述符就绪。    - 其中的 tv_sec 和 tv_usec 成员均为 0 表示非阻塞调用立即返回。 - 时间结构设置为某个特定的时间量秒和微秒这意味着 select 会阻塞但最多等待这段时间。 epoll_wait 和 select 都可以根据需求设置为阻塞或非阻塞。在性能方面select 受制于能够监视的文件描述符数量的限制通常是FD_SETSIZE通常为1024而 epoll 更适合大规模文件描述符的监视因为 epoll 内部使用了不同的机制它不受固定大小限制并且当活动文件描述符的数量远小于总数时它能提供更好的性能。 选择使用 select 或 epoll以及 poll取决于具体的应用需求以及对性能和可扩展性的考量。在现代Linux系统上epoll 通常是大规模且长时间运行的网络服务程序的首选。
  3. 工作方式 在Linux C语言socket编程中epoll_wait和select都是用来监视多个文件描述符的可读、可写、异常等状态的系统调用但它们的工作方式有所不同。 select select函数是POSIX标准的一部分它允许应用程序监视一组文件描述符等待一个或多个文件描述符成为非阻塞状态。select使用一个固定大小的文件描述符集合并且在每次调用select时都需要重新设置文件描述符集和超时时间。这种方法在监控大量文件描述符时效率不高因为它需要线性地检查每一个文件描述符。 epoll epoll系列函数是Linux特有的提供了一种更高效的机制来处理大量文件描述符。epoll使用一个事件表来跟踪每个文件描述符的状态并在文件描述符状态改变时通知应用程序。epoll的优势在于它不需要在每次调用时都重新设置文件描述符集合而且它能以常数时间复杂度管理文件描述符集合这在处理大量文件描述符时可以提供更好的性能。 当使用epoll时通常是通过以下步骤操作的
  4. 使用epoll_create创建一个epoll实例。 2. 使用epoll_ctl添加、修改或删除要监视的文件描述符。
  5. 使用epoll_wait等待事件的发生并处理发生的事件。 如果选择使用epoll系列函数来进行socket编程就不需要使用select函数了因为epoll提供了更高效且功能更完备的替代方案。在处理大规模并发连接时epoll通常是更好的选择。 二、epoll代码示例
  6. python示例 epoll 是 Linux 上的一个高效的 IO 事件通知系统它能够告诉你哪些文件描述符sockets、文件、pipes等已经准备好执行非阻塞的读取或写入操作。与传统的 select 和 poll 相比epoll 在处理大量文件描述符时更加高效。下面是一个简单的 epoll 示例代码。 注意以下示例代码仅适用于 Linux 系统。 import socket import select import errno# 创建一个 TCP/IP 套接字 server_socket socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 设置套接字选项允许我们重新绑定同一个端口 server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)# 绑定套接字到端口 server_address (localhost, 10000) print(开始在 %s 端口 %s 上监听 % server_address) server_socket.bind(server_address)# 监听入站连接 server_socket.listen(1)# 设置非阻塞模式 server_socket.setblocking(0)# 创建一个 epoll 对象 epoll select.epoll()# 在 epoll 事件循环中注册服务器套接字监听读事件 EPOLLIN select.EPOLLIN epoll.register(server_socket.fileno(), EPOLLIN)try:connections {}requests {}responses {}while True:# 等待事件发生可能会使得程序进入阻塞状态events epoll.poll(1)for fileno, event in events:if fileno server_socket.fileno():# 新入站连接connection, client_address server_socket.accept()print(新连接来自, client_address)connection.setblocking(0)# 注册读事件epoll.register(connection.fileno(), EPOLLIN)connections[connection.fileno()] connectionrequests[connection.fileno()] bresponses[connection.fileno()] belif event EPOLLIN:# 可读事件data connections[fileno].recv(1024)if data:print(f接收到 {len(data)} 字节: {data.decode()})requests[fileno] dataelse:# 如果没有数据意味着客户端关闭了连接epoll.unregister(fileno)connections[fileno].close()del connections[fileno], requests[fileno], responses[fileno]elif event select.EPOLLOUT:# TODO: 可写事件处理逻辑# 在这里处理 responses 字典中待发送的数据passelif event select.EPOLLHUP:# TODO: 处理挂起的连接epoll.unregister(fileno)connections[fileno].close()del connections[fileno] finally:# 释放资源epoll.unregister(server_socket.fileno())epoll.close()server_socket.close() 这段代码创建了一个 TCP 服务器它使用 epoll 来管理每个连接的事件。在这个简单的例子中服务器仅仅是读取客户端数据并打印出来。 注意代码中有几个 TODO 注释提示在哪里添加处理可写事件和挂起连接的代码。对于一个完整的服务器通常还需要处理客户端发送的请求并产生响应发送回客户端。 确保在实际运行这段代码前已经对 epoll、非阻塞套接字和事件驱动编程有所理解。通过细读并且动手实践将能够理解在一个高性能网络程序中如何使用 epoll。
  7. C语言示例 Linux C 语言中使用 epoll 的 socket 编程示例相对复杂因为它涉及对 socket API 的理解以及对事件驱动编程模型的使用。以下是一个简单的 epoll 示例这个示例程序的目的是创建一个 TCP echo 服务器它使用 epoll 来处理多个客户端连接。 请注意以下代码将仅作为示教用途它并没有处理所有可能的错误并且不应该在生产环境中直接使用。此外确保在编译时链接到 -lnsl 库如果需要。 #include stdio.h #include stdlib.h #include string.h #include errno.h #include unistd.h #include sys/socket.h #include resolv.h #include arpa/inet.h #include sys/epoll.h#define PORT 12345 #define MAX_EVENTS 32void die(const char *msg) {perror(msg);exit(EXIT_FAILURE); }int main() {int listenfd, connfd, epollfd, nfds, i;struct sockaddr_in addr;struct epoll_event ev, events[MAX_EVENTS];// 创建和绑定 socketlistenfd socket(AF_INET, SOCK_STREAM, 0);if (listenfd 0) die(socket() failed);bzero(addr, sizeof(addr));addr.sin_family AF_INET;addr.sin_port htons(PORT);addr.sin_addr.s_addr INADDR_ANY;if (bind(listenfd, (struct sockaddr *)addr, sizeof(addr)) ! 0)die(bind() failed);// 监听 socketif (listen(listenfd, 10) ! 0)die(listen() failed);// 创建 epoll 实例epollfd epoll_create1(0);if (epollfd 0) die(epoll_create1() failed);ev.events EPOLLIN;ev.data.fd listenfd;if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listenfd, ev) -1)die(epoll_ctl: listenfd);for (;;) {nfds epoll_wait(epollfd, events, MAX_EVENTS, -1);if (nfds 0) die(epoll_wait() failed);for (i 0; i nfds; i) {if (events[i].data.fd listenfd) {connfd accept(listenfd, NULL, NULL);if (connfd 0) die(accept() failed);ev.events EPOLLIN | EPOLLET;ev.data.fd connfd;if (epoll_ctl(epollfd, EPOLL_CTL_ADD, connfd, ev) -1)die(epoll_ctl: connfd);} else {char buffer[256];ssize_t bytes_read;// 处理客户端数据bytes_read read(events[i].data.fd, buffer, sizeof(buffer));if (bytes_read 0) {// 读取完成或者发生错误关闭连接close(events[i].data.fd);} else {buffer[bytes_read] \0;printf(Received: %s, buffer);// Echo 回数据write(events[i].data.fd, buffer, bytes_read);}}}}close(listenfd);return 0; } 在这个示例中我们创建了一个 TCP 服务器 socket并将它绑定到指定的端口这里是 12345。我们对这个 socket 调用了 listen把它变成一个监听 socket并创建了一个 epoll 实例来处理链接事件和数据接收事件。服务器以事件循环的方式运行使用 epoll 等待新事件。 当新的连接到达时它会被接受并添加到 epoll 实例以供监视。当已连接的 socket 有数据可读时服务器会读取这些数据并简单地将其作为 echo 响应发回客户端。 记得在多客户端的情况下还应该考虑
  • 不同客户端之间进行全面的状态管理。 - 对于边缘触发EPOLLET的处理更为复杂需要确保数据完全读取。 - 此代码示例没有使用SSL对于安全连接需要集成SSL库。
  • 更强的错误处理和程序稳健性措施。 三、epoll事件 epoll 是 Linux 下的一种 I/O 事件通知机制它可以高效地处理数以万计的文件描述符。当注册一个文件描述符比如 socket到 epoll 实例时需要指定感兴趣的事件类型。epoll 能够监视多种类型的事件以下是一些常见的 epoll 事件及其含义 1. EPOLLIN表示对应的文件描述符可以读取非高优先级数据比如 TCP Socket 的接收缓冲区非空可以调用 recv()或者 UDP Socket 收到了数据包可以调用 recvfrom()。 2. EPOLLOUT表示对应的文件描述符可以写入数据比如 TCP Socket 的发送缓冲区有空间可以调用 send()。 3. EPOLLPRI表示对应的文件描述符有紧急的数据可读带外数据这适用于 TCP Socket。 4. EPOLLERR表示对应的文件描述符发生了错误。这不必由用户设置即使未指定系统也会报告它。 5. EPOLLHUP表示对应的文件描述符被挂断。如果 Socket 对端关闭了连接或者是某种半关闭状态你会收到这个事件。类似 EPOLLERR这个事件也会不论是否被用户请求都报告它。 6. EPOLLRDHUP自 Linux 2.6.17 版本起表示 Socket 监测到连接的另一端关闭了连接或者半关闭了连接。适用于 TCP Socket。 7. EPOLLET将 epoll 设置为边缘触发Edge Triggered模式这意味着 epoll 仅通知你一次事件直到下一个事件发生不会再次通知你相同的事件。 8. EPOLLONESHOT表示一次性的事件当事件被触发后如果需要再次被触发必须重新设置。 这些事件均适用于 TCP 和 UDP Socket但是某些事件在实际应用中更常用于 TCP如EPOLLRDHUP、EPOLLPRI。由于 TCP 是一个面向连接的协议它支持如连接的建立、数据的可靠传输、流控制等多种事件而 UDP 是一个无连接的协议通常只关心数据的接收与发送EPOLLIN 和 EPOLLOUT。在使用 UDP 时EPOLLERR 也可能被用来处理错误情况。 四、处理EPOLLERR事件 在Linux系统中epoll 是一种高效的 IO 事件通知机制它能够告诉你哪些文件描述符file descriptors, FDs已经准备好进行非阻塞的读写操作。EPOLLERR 是 epoll 等待 (epoll_wait) 函数返回的可能事件之一它表明一个出错的文件描述符。 当 epoll_wait 检测到某个文件描述符上有 EPOLLERR 事件时通常需要采取以下步骤来处理它 1. 识别错误原因当 EPOLLERR 发生时需要确定导致错误的具体原因。可以通过调用 getsockopt 函数与 SO_ERROR 选项来检索和清除该文件描述符的错误状态。 int err;socklen_t errlen sizeof(err);if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)err, errlen) 0) {// Now err contains the error code or 0 if theres no error} err 中可能包含的错误码是一系列定义在 errno.h 头文件中的标准 POSIX 错误码。这些错误码表示了套接字上可能发生的不同错误。以下是一些常见的错误码和它们的含义 - ECONNRESET - 连接被对端重置。 - ETIMEDOUT - 连接尝试超时。 - ECONNREFUSED - 连接被远程主机拒绝。 - EHOSTDOWN - 主机已宕机。 - EHOSTUNREACH - 没有到主机的网络路由。 - EPIPE - 管道破裂通常是在对一个非连接的套接字执行写操作时。 - ENETUNREACH - 网络不可达。 - ENETDOWN - 网络系统不可用。 - EAGAIN 或 EWOULDBLOCK - 资源临时不可用。 处理这些错误通常需要根据应用程序的上下文和设计来决定。以下是一些基本的处理策略 - 重新连接对于 ECONNRESET 或 ETIMEDOUT可能需要尝试重新建立连接。 - 报告错误对于 ECONNREFUSED、EHOSTUNREACH 或 ENETUNREACH应当报告错误给用户并考虑是否需要重试。 - 资源管理对于 EAGAIN 或 EWOULDBLOCK这通常意味着非阻塞操作会在没有立即完成的情况下返回。可能需要稍后再试或者使用异步 I/O。 清除文件描述符的错误状态 在调用 getsockopt 函数并使用 SO_ERROR 选项之后错误状态就被清除了。如果检索到 err 变量中的错误码后这个特定的套接字错误就被认为是 已被消费 的。以后再次调用带 SO_ERROR 选项的 getsockopt 将返回 0除非自从上一次调用以来发生了新的错误。 注意对文件描述符本身的错误状态执行 清除 操作只是指读取出错误信息。如果套接字真正遭受了致命错误比如 ECONNRESET为了恢复将需要关闭它并且取决于情况或许需要创建一个新的套接字来替代。某些错误可能是暂时性的可能可以继续使用现有的套接字但通常还是需要应用程序采取一些形式的恢复措施。
  1. 响应错误错误的具体原因将决定你的下一步行动。有时可能需要关闭并重新打开文件描述符其他情况下可能需要记录错误并通知应用程序其他部分。 3. 关闭文件描述符如果文件描述符因错误不再可用应该关闭它。继续使用一个出现错误的文件描述符可能导致未定义行为。 close(fd);
  2. 清理资源如果该文件描述符是某种资源的一部分例如一个客户端连接确保适当地清理资源例如释放内存、取消定时器等。 5. 日志记录记录日志信息可以帮助调试和跟踪系统的行为尤其是错误条件发生时。 6. 用户通知如有必要如果错误会影响用户操作你可能需要通知用户或启动一些恢复流程。 值得注意的是EPOLLERR 通常与其他 I/O 事件EPOLLIN、EPOLLOUT 等一起返回表示即使有错误文件描述符也可能处于可读或可写状态。但是处理读写之前应该始终先检查和响应错误。此外对于某些类型的文件描述符如 epoll 自己的文件描述符EPOLLERR 也可能意味着某些系统层面的问题你需要具备相应的处理逻辑。 五、EPOLLHUP和EPOLLRDHUP事件的区别 EPOLLHUP和EPOLLRDHUP是Linux提供的epoll机制中的两个事件用于监控文件描述符的状态变化。这两个事件与网络编程中的socket状态变化有关尤其是在处理TCP连接时。以下是它们的定义和区别EPOLLHUP挂起事件 - EPOLLHUP标志用于表示一个挂起的事件。这通常意味着文件描述符被挂断无更多的读写操作能够执行无论是另一端的正常关闭如调用close()还是因为某种错误而非正常关闭。 - EPOLLHUP事件表明连接已经完全关闭或者对应的socket出现了一些异常不再可用。 - 在某些情况下即使没有向epoll注册EPOLLHUP事件epoll_wait仍然可能返回该事件。这是因为EPOLLHUP被视为一个异常事件epoll希望你能够注意到并采取适当的行动。EPOLLRDHUP读挂断事件 - EPOLLRDHUP是在Linux内核2.6.17中引入的一个标志用于表示对端的socket已经关闭了写操作或者说执行了半关闭关闭了连接的写入部分。它通常用于检测TCP连接的这种半关闭状态。 - EPOLLRDHUP事件可以让程序更加精细地检测到对方是否还在发送数据或者只是单方面关闭了发送通道。可以在检测到EPOLLRDHUP后继续从socket读取直到得到EOF这时才真正意味着对方完成了所有发送。 - 如果希望通过epoll监测这个事件需要显式地在注册epoll事件时指定EPOLLRDHUP。区别 - EPOLLHUP通常用来表示文件描述符完全不可用了不再连接。 - EPOLLRDHUP用来表示对端关闭了写半部分半关闭状态本端仍可以读取剩余数据。实际用法中的注意 - 在编写使用epoll机制的网络编程时应当注意处理EPOLLHUP和EPOLLRDHUP事件。例如一个web服务器需要知道什么时候客户端关闭了连接这样才能使资源得到及时释放。 - EPOLLRDHUP在TCP连接管理中尤其有用它允许服务端检测到客户端的半关闭状态从而能够优雅地关闭连接。 - 当使用epoll时记得仔细区分并处理这两种事件避免误解它们的意图而导致bug或资源泄漏。 总结来说EPOLLRDHUP和EPOLLHUP都是与连接关闭有关的事件但具体的语义和用途是有区别的。理解并正确处理这些事件对于开发稳定和高效的网络服务是非常关键的。 六、EPOLLPRI事件 在网络编程中有两种数据传输方式普通数据传输和带外数据传输。普通数据是应用程序正常通信的数据它们遵循正常的数据流和处理顺序。而带外数据也称作紧急数据是一种特殊的传输方式使得某些数据能够越过正常的数据流得到网络栈以及应用程序的优先处理。 带外数据主要特征如下 1. 优先级高带外数据被设计为有更高的优先级它会被发送和接收的过程中优先对待。 2. 数量少相对于普通数据带外数据通常不用于大量数据的传输而是发送少量紧急信息。 3. 单独的通道带外数据经常被看作是通过一个独立的通道进行传输以便在接收端立刻被注意到并处理它与普通数据流分开。 4. 紧急通知带外数据通常用于告知远端系统某种紧急状况或者控制信息如TCP协议中的紧急指针字段被用于通知接收端有紧急数据要处理。 在TCP/IP协议中带外数据通常是通过TCP的URG紧急标志位来实现的。当一个TCP段设置了URG标志位时紧跟在TCP头之后的数据被标记为紧急数据。收到这样的TCP段时操作系统会通知应用程序有紧急数据到达。 在应用程序层面带外数据通常通过特定的API调用来发送和接收。例如在套接字编程中可通过设置SO_OOBINLINE的套接字选项决定是在正常数据流中接收带外数据还是通过特定的带外数据机制处理它们。 带外数据的一个常见应用示例是中断远程服务器上长时间运行的进程。例如用户可能发送一个紧急数据包来通知服务器立即停止当前的传输。 然而需要注意的是不是所有的协议或系统都支持带外数据。在实际应用中带外数据由于其复杂性和一致性问题并不经常使用很多新的协议和应用都避免使用它。在设计现代网络应用时更通常的做法是在应用层面设定协议来处理紧急情况而不是依赖底层网络的带外数据功能。 七、epoll_create和epoll_create1有什么不同 epoll_create 和 epoll_create1 都是用来创建一个新的 epoll 实例的系统调用但它们之间有一些差异 1. epoll_create:    - 在较旧的 Linux 内核版本中引入。    - 需要一个参数 size该参数在早期用于告诉内核监听的文件描述符数量。然而在现代 Linux 内核中这个参数并不起作用因为 epoll 会根据需要动态调整但出于向后兼容性的原因这个参数必须大于零。    - 用法示例int epoll_fd epoll_create(1);    - 不接受标志flags参数所以创建的 epoll 文件描述符总是具有相同的属性。 2. epoll_create1:    - 在较新的 Linux 内核版本2.6.27 及之后版本中引入。    - 添加了一个参数 flags它允许你改变 epoll 文件描述符的行为例如设置为非阻塞。    - flags 参数可以是以下之一       - 0效果与 epoll_create 相同。       - EPOLL_CLOEXEC使用这个标志创建的 epoll 文件描述符在执行 exec 系列调用产生的新进程中将会被自动关闭。这有助于防止文件描述符泄漏到子进程。    - 如果不需要设置任何标志可以传入 0 作为 flags 的值。    - 用法示例int epoll_fd epoll_create1(0); 或者 int epoll_fd epoll_create1(EPOLL_CLOEXEC); 总体来说epoll_create1 提供了更多的控制和扩展性并且是推荐使用的方式如果你的环境中存在支持它的 Linux 内核版本。如果仅需要创建一个 epoll 实例而不考虑 exec 调用中的文件描述符行为那么使用 0 作为 flags 的值就足够了。  八、普通文件并不是epoll支持的文件描述符类型 错误 epoll_ctl: Operation not permitted 通常发生在尝试对不支持epoll操作的文件描述符执行epoll_ctl()时。Epoll 主要用于I/O多路复用它适用于套接字、管道和其他一些特定类型的文件描述符这些文件描述符应该是可边缘触发的ET或水平触发的LT。 普通文件如尝试打开的 test.txt并不是epoll支持的文件描述符类型。对于普通文件因为它们总是准备好被读取或写入所以epoll机制不适用。普通文件的I/O是非阻塞的epoll等待机制仅适用于可能阻塞的操作如套接字I/O。 如果目的是监视文件的变化可以考虑使用 inotify 机制而不是 epoll。inotify 机制是用来监视文件系统事件的比如文件的创建、修改、删除等。 然而如果仍希望使用 epoll需要使用它来监视套接字之类的文件描述符而不是常规文件。对于常规文件I/O可以直接使用 read()、write() 等系统调用通常不需要使用 epoll 这样的机制。 如果需要使用epoll监控文件描述符则可以测试套接字的场景。例如可以创建一个简单的网络服务使用套接字并使用epoll来处理来自客户端的连接和数据。