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

网站建设的关键技术关键词查询网址

网站建设的关键技术,关键词查询网址,自己做的网站点首页出错,点击app图标进入网站怎么做网络I/O模型 同步I/O阻塞I/O非阻塞I/OI/O多路复用select函数接口示例 poll函数接口示例 poll 和 select 的区别epoll原理:示例 异步I/O 同步I/O 阻塞I/O 一个基本的C/S模型如下图所图:其中 listen()、connect()、write()、read() 都是阻塞I/O&#xff0…

网络I/O模型

  • 同步I/O
    • 阻塞I/O
    • 非阻塞I/O
    • I/O多路复用
      • select
        • 函数接口
        • 示例
      • poll
        • 函数接口
        • 示例
      • poll 和 select 的区别
      • epoll
        • 原理:
        • 示例
  • 异步I/O

同步I/O

阻塞I/O

Alt

一个基本的C/S模型如下图所图:其中 listen()、connect()、write()、read() 都是阻塞I/O,用户态的进程在执行这些操作时会陷入内核态并被挂起。直到 socket() 上有数据可读/写时,进程才会从内核态切换到用户态,并完成数据在内核态和用户态之间的复制。

int fd = open("file.txt", O_RDONLY);
char buffer[100];
ssize_t bytes_read = read(fd, buffer, sizeof(buffer));	// 阻塞
close(fd);

非阻塞I/O

Alt

I/O多路复用

select

select() 函数是一个用于多路复用I/O的系统调用,允许程序同时监控多个文件描述符(如套接字、管道、终端等)的可读、可写或异常状态。

函数接口
#include <sys/select.h>int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

其中:

  • nfds: 整型变量,表示在所有集合中最大的文件描述符加1。这是为了告诉select()需要检查的文件描述符范围。实际上,你只需要提供所有被监控的文件描述符中的最大值加1即可。
  • readfds: 指向fd_set结构的指针,用于存放待检查可读性的文件描述符集合。如果某个文件描述符在此集合中并且变为可读,select()返回后,该文件描述符在集合中的状态仍会被保持为已设置。
  • writefds: 用于存放待检查可写性的文件描述符集合。
  • exceptfds: 用于存放待检查异常条件的文件描述符集合。
  • timeout: 指向timeval结构的指针,用来指定select()调用的最大等待时间。如果为NULL,select()将一直阻塞直到有文件描述符满足条件;如果不为NULL且值为(0, 0),则select()会立即返回,不进行等待;如果指定了具体的时间,则select()最多等待指定的时间。

返回值

  • 正值: 返回的是已就绪的文件描述符的数量(包括可读、可写或异常的)。注意,这个值并不直接告诉你哪些描述符就绪,你需要通过FD_ISSET宏检查集合来确定具体哪些描述符准备好了。

  • 0: 表示在指定的超时时间内没有文件描述符变为就绪状态。

  • -1: 表示调用出错,此时可以查看errno来获取具体的错误信息。

示例
void updateReadSet(std::unordered_set<int> &clientFds, int &maxFd, int sockFd, fd_set &readSet) {maxFd = sockFd;FD_ZERO(&readSet);FD_SET(sockFd, &readSet);for (const auto &clientFd : clientFds) {if (clientFd > maxFd) {maxFd = clientFd;}FD_SET(clientFd, &readSet);}
}void handlerClient(int clientFd) {std::string msg;if (not EchoServer::RecvMsg(clientFd, msg)) {return;}EchoServer::SendMsg(clientFd, msg);
}int main(int argc, char *argv[]) {if (argc != 3) {std::cout << "invalid input" << std::endl;std::cout << "example: ./Select 0.0.0.0 1688" << std::endl;return -1;}int sockFd = EchoServer::CreateListenSocket(argv[1], atoi(argv[2]), false);if (sockFd < 0) {return -1;}int maxFd;fd_set readSet;EchoServer::SetNotBlock(sockFd);std::unordered_set<int> clientFds;while (true) {updateReadSet(clientFds, maxFd, sockFd, readSet);int ret = select(maxFd + 1, &readSet, NULL, NULL, NULL);if (ret <= 0) {if (ret < 0) perror("select failed");continue;}for (int i = 0; i <= maxFd; i++) {if (not FD_ISSET(i, &readSet)) {continue;}if (i == sockFd) {  // 监听的sockFd可读,则表示有新的链接EchoServer::LoopAccept(sockFd, 1024, [&clientFds](int clientFd) {clientFds.insert(clientFd);  // 新增到要监听的fd集合中});continue;}handlerClient(i);clientFds.erase(i);close(i);}}return 0;
}

poll

在 select() 中文件描述符集合是由一个大小为1024的位图实现的,为了支持监听更多的文件描述符,poll 结构体数组存放描述符集合。

struct pollfd {int   fd;		// 文件描述符short events;	// 监听的事件short revents;	// 返回的事件
}
函数接口
#include <poll.h>
// nfds 指明fds数组的大小
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
示例
void updateFds(std::unordered_set<int> &clientFds, pollfd **fds, int &nfds) {if (*fds != nullptr) {delete[](*fds);}nfds = clientFds.size();*fds = new pollfd[nfds];int index = 0;for (const auto &clientFd : clientFds) {(*fds)[index].fd = clientFd;(*fds)[index].events = POLLIN;(*fds)[index].revents = 0;index++;}
}void handlerClient(int clientFd) {std::string msg;if (not EchoServer::RecvMsg(clientFd, msg)) {return;}EchoServer::SendMsg(clientFd, msg);
}int main(int argc, char *argv[]) {if (argc != 3) {std::cout << "invalid input" << std::endl;std::cout << "example: ./Poll 0.0.0.0 1688" << std::endl;return -1;}int sockFd = EchoServer::CreateListenSocket(argv[1], atoi(argv[2]), false);if (sockFd < 0) {return -1;}int nfds = 0;pollfd *fds = nullptr;std::unordered_set<int> clientFds;clientFds.insert(sockFd);EchoServer::SetNotBlock(sockFd);while (true) {updateFds(clientFds, &fds, nfds);int ret = poll(fds, nfds, -1);if (ret <= 0) {if (ret < 0) perror("poll failed");continue;}for (int i = 0; i < nfds; i++) {if (not(fds[i].revents & POLLIN)) {continue;}int curFd = fds[i].fd;if (curFd == sockFd) {EchoServer::LoopAccept(sockFd, 1024, [&clientFds](int clientFd) {clientFds.insert(clientFd);  // 新增到要监听的fd集合中});continue;}handlerClient(curFd);clientFds.erase(curFd);close(curFd);}}return 0;
}

poll 和 select 的区别

  1. 数据结构和参数
  • select: 使用固定大小的位图(fd_set)来表示文件描述符集合,上限为1024.
  • poll: 使用动态数组(pollfd 结构体数组)来表示文件描述符集合。
  1. 性能
  • select: 每次调用时,用户态的文件描述符集合需要复制到内核态。
  • poll: 通过传递指针的方式避免了每次调用时复制整个文件描述符集合到内核。

epoll

原理:
  • 事件注册:使用epoll_create创建一个epoll文件描述符,然后通过epoll_ctl向这个文件描述符注册事件(如读、写、错误等)和对应的socket描述符。

  • 事件等待:通过epoll_wait函数等待一个或多个事件的发生。这个调用是阻塞的,直到至少有一个已注册的事件发生,或者超时,或者被中断。相比于select和poll,epoll_wait的优势在于它不会随着监听的文件描述符数量增加而导致效率下降,因为它内部维护了一个高效的红黑树结构来管理这些描述符。

  • 事件处理:当epoll_wait返回时,会给出一个就绪事件的列表,应用可以直接对这些事件进行处理,而无需遍历所有监控的文件描述符

水平触发和边缘触发:

  • LT模式下,只要事件未被处理,每次调用epoll_wait都会返回该事件。
  • ET模式下,事件仅在状态发生变化的那一刻返回一次,要求应用程序一次性处理完所有就绪的数据,否则可能会丢失事件。
示例
void handlerClient(int clientFd) {std::string msg;if (not EchoServer::RecvMsg(clientFd, msg)) {return;}EchoServer::SendMsg(clientFd, msg);
}int main(int argc, char *argv[]) {if (argc != 3) {std::cout << "invalid input" << std::endl;std::cout << "example: ./Epoll 0.0.0.0 1688" << std::endl;return -1;}int sockFd = EchoServer::CreateListenSocket(argv[1], atoi(argv[2]), false);if (sockFd < 0) {return -1;}epoll_event events[2048];int epollFd = epoll_create(1024);if (epollFd < 0) {perror("epoll_create failed");return -1;}EchoServer::Conn conn(sockFd, epollFd, false);EchoServer::SetNotBlock(sockFd);EchoServer::AddReadEvent(&conn);while (true) {int num = epoll_wait(epollFd, events, 2048, -1);if (num < 0) {perror("epoll_wait failed");continue;}for (int i = 0; i < num; i++) {EchoServer::Conn *conn = (EchoServer::Conn *)events[i].data.ptr;if (conn->Fd() == sockFd) {EchoServer::LoopAccept(sockFd, 2048, [epollFd](int clientFd) {EchoServer::Conn *conn = new EchoServer::Conn(clientFd, epollFd, false);EchoServer::AddReadEvent(conn);                 // 监听可读事件,保持fd为阻塞IOEchoServer::SetTimeOut(conn->Fd(), 0, 500000);  // 设置读写超时时间为500ms});continue;}handlerClient(conn->Fd());EchoServer::ClearEvent(conn);delete conn;}}return 0;
}

异步I/O

http://www.hkea.cn/news/66345/

相关文章:

  • 百度网站公司信息推广怎么做天津做网站的网络公司
  • wordpress在线pdfseo百度站长工具查询
  • 太仓网站建设有限公司网站设计公司怎么样
  • 网站去哪做在线crm软件
  • 做360手机网站快速汕头seo排名收费
  • 网站建设总做总结宜兴百度推广公司
  • 做毕业网站的周记外贸建站优化
  • 南昌市住房和城乡建设局网站百度官网推广平台电话
  • 真人做视频网站百度怎么发布广告
  • 网站页面优化包括怎么给网站做优化
  • 哪个网站用帝国cms做的软文素材网
  • 网站建设需要的资料深圳精准网络营销推广
  • 客户网站建设公司网站排名提升软件
  • 网站建设与维护试卷论文怎么在百度上做广告
  • 做博客网站要什么技术百度网站网址是多少
  • 河北建设厅官方网站八大员考试站长工具查询
  • 大连 做网站公司爱站工具包的主要功能
  • ps做简洁大气网站必应bing国内版
  • 做公司标志用哪个网站营销自动化
  • wordpress5.0.3厦门百度seo
  • 网站开发 企业 定制系统优化大师安卓版
  • 网站内链符号seo百度站长工具
  • 网站页面太多是否做静态seo优化软件
  • mac下怎么安装wordpress关键词排名优化易下拉霸屏
  • 国内做国外代购在哪个网站好百度平台客服怎么联系
  • 菏泽网站获客网站建设公司中国站长网入口
  • 黄冈网站建设推荐seo查询排名软件
  • 自己怎么做百度网站广州seo网站公司
  • 京东企业的电子网站建设百度seo教程网
  • 弥勒网站设计公司share群组链接分享