使用epoll时需要将socket设为非阻塞吗?

2023-12-05

本文是回答一位知友的提问:

在APUE中介绍select和poll中说“一个描述阻塞与否并不影响select是否阻塞。也就是说,如果希望读一个非阻塞描述符,并且以超时值5s调用select,则select最多阻塞5s。” 我看到有些程序使用epoll时,使用fcntl将描述符置为非阻塞。这个和上面描述的有冲突没?

一、结论

提出这个问题说明对网络编程的一些基础原理未搞明白,先说下结论:

一个 socket 是否设置为阻塞模式,只会影响到 connect/accept/send/recv 等四个 socket API 函数,不会影响到 select/poll/epoll_wait 函数,后三个函数的超时或者阻塞时间是由其函数自身参数控制的。

二、原理分析

下面详细的解释,为了方便解释,在这之前我们先明确几个基础概念:

connfd:创建 socket,主动发起连接的一端(客户端),该端调用 connect 函数主动发起连接; listenfd:创建 socket,绑定地址和端口,调用 listen 函数发起侦听的一端(服务端); clientfd:调用 accept 函数接受连接,由 accept 函数返回的 socket(服务端)。

示意图如下:

accept 函数并不参与三次握手过程,accept 函数从已经连接的队列中取出连接,返回 clientfd,最后客户端与服务端分别通过 connfd 和 clientf 进行通信(调用 send 或者 recv 函数)。

2.1 socket 是否被设置成阻塞模式对下列 API 造成的影响

1. 当 connfd 被设置成阻塞模式时(默认行为,无需设置),connect 函数会一直阻塞到连接成功或超时或出错,超时值需要修改内核参数(超时和重试规则我在《 C++ 服务器开发精髓 》一书的 5.8 节详细地介绍了)。

2. 当 connfd 被设置成非阻塞模式,无论连接是否建立成功,connect 函数都会立刻返回,那如何判断 connect 函数是否连接成功呢?接下来使用 select 和 poll 函数去判断 socket 是否可写即可,当然,Linux 系统上还需要额外加一步——使用 getsockopt函数判断此时 socket 是否有错误,这就是所谓的异步 connect 或者叫非阻塞 connect(这是实际网络编程中写的比较多的逻辑,也是面试高频题)。

Windows 上的异步 connect 代码示例

//代码节选自:
//https://github.com/balloonwj/flamingo/blob/master/flamingoclient/Source/net/IUSocket.cpp
bool CIUSocket::Connect(int timeout /*= 3*/)
{
    Close();

    m_hSocket = ::socket(AF_INET, SOCK_STREAM, 0);
    if (m_hSocket == INVALID_SOCKET)
        return false;

    long tmSend = 3 * 1000L;
    long tmRecv = 3 * 1000L;
    long noDelay = 1;
    setsockopt(m_hSocket, IPPROTO_TCP, TCP_NODELAY, (LPSTR)&noDelay, sizeof(long));
    setsockopt(m_hSocket, SOL_SOCKET, SO_SNDTIMEO, (LPSTR)&tmSend, sizeof(long));
    setsockopt(m_hSocket, SOL_SOCKET, SO_RCVTIMEO, (LPSTR)&tmRecv, sizeof(long));

    //将socket设置成非阻塞的
    unsigned long on = 1;
    if (::ioctlsocket(m_hSocket, FIONBIO, &on) == SOCKET_ERROR)
        return false;

    struct sockaddr_in addrSrv = { 0 };
    struct hostent* pHostent = NULL;
    unsigned int addr = 0;

    if ((addrSrv.sin_addr.s_addr = inet_addr(m_strServer.c_str())) == INADDR_NONE)
    {
        pHostent = ::gethostbyname(m_strServer.c_str());
        if (!pHostent)
        {
            LOG_ERROR("Could not connect server:%s, port:%d.", m_strServer.c_str(), m_nPort);
            return false;
        }
        else
            addrSrv.sin_addr.s_addr = *((unsigned long*)pHostent->h_addr);
    }

    addrSrv.sin_family = AF_INET;
    addrSrv.sin_port = htons((u_short)m_nPort);
    int ret = ::connect(m_hSocket, (struct sockaddr*) & addrSrv, sizeof(addrSrv));
    if (ret == 0)
    {
        LOG_INFO("Connect to server:%s, port:%d successfully.", m_strServer.c_str(), m_nPort);
        m_bConnected = true;
        return true;
    }
    else if (ret == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK)
    {
        LOG_ERROR("Could not connect to server:%s, port:%d.", m_strServer.c_str(), m_nPort);
        return false;
    }

    fd_set writeset;
    FD_ZERO(&writeset);
    FD_SET(m_hSocket, &writeset);
    struct timeval tv = { timeout, 0 };
    if (::select(m_hSocket + 1, NULL, &writeset, NULL, &tv) != 1)
    {
        LOG_ERROR("Could not connect to server:%s, port:%d.", m_strServer.c_str(), m_nPort);
        return false;
    }

    m_bConnected = true;

    return true;
}

Linux 上异步 connect 代码示例:

//代码节选自:
//https://github.com/balloonwj/mybooksources/blob/master/Chapter04/code/linux_nonblocking_connect.cpp
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>

#define SERVER_ADDRESS "127.0.0.1"
#define SERVER_PORT     3000
#define SEND_DATA       "helloworld"

int main(int argc, char* argv[])
{
    //1.创建一个socket
    int clientfd = socket(AF_INET, SOCK_STREAM, 0);
    if (clientfd == -1)
    {
        std::cout << "create client socket error." << std::endl;
        return -1;
    }

    //将clientfd设置成非阻塞模式
    int oldSocketFlag = fcntl(clientfd, F_GETFL, 0);
    int newSocketFlag = oldSocketFlag | O_NONBLOCK;
    if (fcntl(clientfd, F_SETFL,  newSocketFlag) == -1)
    {
        close(clientfd);
        std::cout << "set socket to nonblock error." << std::endl;
        return -1;
    }

    //2.连接服务器
    struct sockaddr_in serveraddr;
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = inet_addr(SERVER_ADDRESS);
    serveraddr.sin_port = htons(SERVER_PORT);
    for (;;)
    {
        int ret = connect(clientfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
        if (ret == 0)
        {
            std::cout << "connect to server successfully." << std::endl;
            close(clientfd);
            return 0;
        }
        else if (ret == -1)
        {
            if (errno == EINTR)
            {
                //connect 动作被信号中断,重试connect
                std::cout << "connecting interruptted by signal, try again." << std::endl;
                continue;
            }
            else if (errno == EINPROGRESS)
            {
                //连接正在尝试中
                break;
            }
            else
            {
                //真的出错了,
                close(clientfd);
                return -1;
            }
        }
    }

    fd_set writeset;
    FD_ZERO(&writeset);
    FD_SET(clientfd, &writeset);
    struct timeval tv;
    tv.tv_sec = 3;
    tv.tv_usec = 0;
    //3.调用select函数判断socket是否可写
    if (select(clientfd + 1, NULL, &writeset, NULL, &tv) != 1)
    {
        std::cout << "[select] connect to server error." << std::endl;
        close(clientfd);
        return -1;
    }

    int err;
    socklen_t len = static_cast<socklen_t>(sizeof err);
    //4.调用getsockopt检测此时socket是否出错
    if (::getsockopt(clientfd, SOL_SOCKET, SO_ERROR, &err, &len) < 0)
    {
        close(clientfd);
        return -1;
    }

    if (err == 0)
        std::cout << "connect to server successfully." << std::endl;
    else
        std::cout << "connect to server error." << std::endl;
    
    close(clientfd);

    return 0;
}

https://github.com/balloonwj/mybooksources/blob/master/Chapter04/code/linux_nonblocking_connect_poll.cpp

3. 当 listenfd 设置成阻塞模式(默认行为,无需额外设置)时,如果连接 pending 队列中有需要处理的连接,accept 函数会立即返回,否则会一直阻塞下去,直到有新的连接到来。

4. 当 listenfd 设置成非阻塞模式,无论连接 pending 队列中是否有需要处理的连接,accept 都会立即返回,不会阻塞。如果有连接,则 accept 返回一个大于 0 的值,这个返回值即是我们上文所说的 clientfd;如果没有连接,accept 返回值小于 0,错误码 errno 为 EWOULDBLOCK(或者是 EAGAIN,这两个错误码值相等)。我们以 Redis 接受连接的代码为例吧:

//代码节选自Redis,
//https://github.com/balloonwj/mybooksources/blob/master/Chapter02/redis-6.0.3/src/networking.c
//971行
void acceptTcpHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
    int cport, cfd, max = MAX_ACCEPTS_PER_CALL;
    char cip[NET_IP_STR_LEN];
    UNUSED(el);
    UNUSED(mask);
    UNUSED(privdata);

    while(max--) {
        //anetTcpAccept函数内部调用的是accept函数
        cfd = anetTcpAccept(server.neterr, fd, cip, sizeof(cip), &cport);
        if (cfd == ANET_ERR) {
            //fd是非阻塞的listenfd,当没有连接时,accept函数返回-1,错误码errno为EWOULDBLOCK
            if (errno != EWOULDBLOCK)
                serverLog(LL_WARNING,
                    "Accepting client connection: %s", server.neterr);
            return;
        }
        serverLog(LL_VERBOSE,"Accepted %s:%d", cip, cport);
        acceptCommonHandler(connCreateAcceptedSocket(cfd),0,cip);
    }
}

5. 当 connfd 或 clientfd 设置成阻塞模式时:send 函数会尝试发送数据,如果对端因为 TCP 窗口太小导致本端无法将数据发送出去,send 函数会一直阻塞直到对端 TCP 窗口变大足以发数据或者超时;recv 函数则正好相反,如果此时没有数据可收获,recv函数会一直阻塞直到收取到数据或者超时,有的话,取到数据后返回。send 和 recv 函数的超时时间可以分别使用 SO_SNDTIMEO 和 SO_RCVTIMEO 两个 socket 选项来设置。示例代码如下:

long tmSend = 3 * 1000L;
long tmRecv = 3 * 1000L;
//将send函数的超时时间设置为3秒   
setsockopt(m_hSocket, SOL_SOCKET, SO_SNDTIMEO, (LPSTR)&tmSend, sizeof(long));
//将recv函数的超时时间设置为3秒
setsockopt(m_hSocket, SOL_SOCKET, SO_RCVTIMEO, (LPSTR)&tmRecv, sizeof(long));

6. 当 connfd 或 clientfd 设置成非阻塞模式时,send 和 recv 函数都会立即返回,send 函数即使因为对端 TCP 窗口太小发不出去也会立即返回,recv 函数如果无数据可收也会立即返回,此时这两个函数的返回值都是 -1,错误码 errno 是 EWOULDBLOCK(或 EAGIN,与上面同)。这种情况下,send 和 recv 函数的返回值有三种情形,分别是大于 0,等于0 和小于 0,总结如下表:

三、select/poll/epoll_wait 函数的等待或超时时间

select、poll、epoll_wait 函数的超时时间分别有传给各自函数的时间参数决定的,我们来看下这三个函数的签名:

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);

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

三个函数最后一个参数是 timeout,只不过 select 函数的 timeout 参数的类型是一个结构体指针,这个结构的定义如下:

struct timeval 
{
    long    tv_sec;         /* seconds */
    long    tv_usec;        /* microseconds */
};

select 函数的总超时时间是 timeout->tv_sec 和 timeout->tv_usec 之和, 前者的时间单位是秒,后者的时间单位是微秒。

select 函数的 timeout 参数含义有三种:

  1. 当 timeout 为 NULL 时,select 函数将一直阻塞下去,直到出错或者绑定其上的 socket 有事件;

2. 当 timeout->tv_sec 和 timeout->tv_usec 同时为 0 时,select 函数会检查一下绑定在其上的 socket 是否有事件,然后立刻返回;

3. 当 timeout->tv_sec 和 timeout->tv_usec 之和大于 0 时,select 函数检测到绑定其上的 socket 有时间才会返回或者阻塞时长为 timeout->tv_sec + timeout->tv_usec 。

poll 和 epoll_wait 函数的超时时间为毫秒,设置为 0,和 select 函数一样,检测一下绑定其上的 socket 是否有事件,然后立即返回。

四、使用 epoll 模型是否要将 socket 设置成非阻塞的

答案是需要的。

epoll 模型通常用于服务端,那讨论的 socket 只有 listenfd 和 clientfd 了。

listenfd 为什么一定要设置成非阻塞的,我在另外一篇文章中写的很清楚:

高性能网络通信库中为何要将侦听 socket 设置成非阻塞的?

现在就剩下 clientfd 了,如果不将 clientfd 设置成非阻塞模式,那么一旦 epoll_wait 检测到读或者写事件返回后,接下来处理 clientfd 的读或写事件,如果对端因为 TCP 窗口太小,send 函数刚好不能将数据全部发送出去,将会造成阻塞,进而导致整个服务“卡住”。

五、总结与学习建议

题主提出这样的问题,建议还是加强基础原理和概念的理解,搞清楚每一种技术用于何种场景,例如非阻塞 socket 用于何种场景、影响哪些返回,I/O 复用函数为何阻塞或等待。

六、推荐的一些学习资源

可以从哪里系统地学习到上述知识?

有同学私信问我,你这些知识从哪里学习的呢?

如果你是网络编程零基础或者觉得自己网络编程存在夹生饭问题,推荐看看尹圣雨的《TCP/IP 网络编程》,这本书同时兼顾 Windows 和 Linux 两个平台,使用的是 C 语言和操作系统的 Socket API,通过这本书你能学会常用的操作系统 Socket API 和常用的网络模型,认真学完之后,你不会再纠结同步异步、阻塞非阻塞等概念。

TCP/IP 网络编程

链接: https://pan.baidu.com/s/1ho3e1POq5LzEQWp0Gm2Nsg 提取码: sp8p

接着如果你想编写高性能的网络框架或者高效的服务,推荐游双老师的《Linux 高性能服务器编程》一书。

Linux 高性能服务器编程

链接: https://pan.baidu.com/s/1f9IErU5JP2sw-5Crha9vzg 提取码: je7g

完整的书单在这里:

计算机必看经典书籍(含下载方式)

当然,我自己也出版了一本书《 C++ 服务器开发精髓 》:

在这本书的第四章等章节,我详细地通过循序渐进的方式介绍了网络编程的二十多个重难点知识,当然也包括上文说的阻塞/非阻塞模式、epoll 模型等,这是图书的第四章目录,有兴趣的读者可以阅读一下:

第4章 网络编程重难点解析 282

4.1 学习网络编程时应该掌握的socket函数 282

4.1.1 在Linux上查看socket函数的帮助信息 283

4.1.2 在Windows上查看socket函数的帮助信息 285

4.2 TCP网络通信的基本流程 286

4.3 设计跨平台网络通信库时的一些socket函数用法 290

4.3.1 socket数据类型 290

4.3.2 在Windows上调用socket函数 290

4.3.3 关闭socket函数 291

4.3.4 获取socket函数的错误码 291

4.3.5 套接字函数的返回值 293

4.3.6 select函数第1个参数的问题 293

4.3.7 错误码WSAEWOULDBLOCK和EWOULDBLOCK 294

4.4 bind函数重难点分析 294

4.4.1 对bind函数如何选择绑定地址 294

4.4.2 bind函数的端口号问题 295

4.5 select函数的用法和原理 302

4.5.1 Linux上的select函数 302

4.5.2 Windows上的select函数 317

4.6 socket的阻塞模式和非阻塞模式 318

4.6.1 如何将socket设置为非阻塞模式 318

4.6.2 send和recv函数在阻塞和非阻塞模式下的表现 320

4.6.3 非阻塞模式下send和recv函数的返回值总结 331

4.6.4 阻塞与非阻塞socket的各自适用场景 333

4.7 发送0字节数据的效果 333

4.8 connect函数在阻塞和非阻塞模式下的行为 339

4.9 连接时顺便接收第1组数据 343

4.10 如何获取当前socket对应的接收缓冲区中的可读数据量 346

4.10.1 分析 346

4.10.2 注意事项 350

4.11 Linux EINTR错误码 351

4.12 Linux SIGPIPE信号 352

4.13 Linux poll 函数的用法 353

4.14 Linux epoll模型 361

4.14.1 基本用法 361

4.14.2 epoll_wait与poll函数的区别 363

4.14.3 LT 模式和ET 模式 363

4.14.4 EPOLLONESHOT 选项 380

4.15 高效的readv和writev函数 386

4.16 主机字节序和网络字节序 387

4.16.1 主机字节序 387

4.16.2 网络字节序 388

4.16.3 操作系统提供的字节转换函数汇总 389

4.17 域名解析API介绍 390

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用epoll时需要将socket设为非阻塞吗? 的相关文章

  • 通过自定义文本更改库存文本中的 WooCommerce 产品可用性

    我想更改库存数量后面的 有库存 文字 我尝试在我的 WordPress php 编辑器中添加此 PHP 代码 但它不起作用 你知道为什么吗 谢谢 add filter woocommerce get availability text bb
  • SQL Server、ISABOUT、加权项

    我试图弄清楚加权项在 SQL SERVER 的 ISABOUT 查询中是如何工作的 这是我目前所在的位置 每个查询返回以下行 查询 1 权重 1 初始排名 SELECT FROM CONTAINSTABLE documentParts ti
  • 在 SQL Server 中选择条件的值[重复]

    这个问题在这里已经有答案了 在查询选择中 我想显示字段是否满足条件的结果 想象一下我有一张名为stock 该表有一列告诉我库存中每种商品的数量 我想做的是这样的 SELECT stock name IF stock quantity lt
  • 将 Javascript 正则表达式转换为 PHP

    我知道这个问题已经被问了大约十几次 但是从技术上讲 这个问题并不是一个骗局 如果您愿意 请检查其他问题 基本上 我有一个 Javascript 正则表达式来检查用于前端验证的电子邮件地址 并且我使用 CodeIgniter 在后端进行双重检
  • 关系数据库和图数据库的比较

    有人可以向我解释一下 MySQL 等关系数据库与 Neo4j 等图形数据库相比的优缺点吗 在 SQL 中 您有多个表 它们之间有不同的 id 链接 然后你必须加入来连接表 从新手的角度来看 为什么要将数据库设计为需要联接 而不是像图形数据库
  • 使用 PHP 简单 HTML DOM 将隐藏的输入标记值作为字符串获取

    我试图获取输入类型隐藏标记值 CAS AH 11 等 以及名称属性 但在运行基于 PHP 的解析器时我得到的只是一个空白页 有人知道出了什么问题吗 我已经查过了将隐藏输入作为字符串抓取 使用 PHP 简单 HTML DOM 解析器 http
  • Ubuntu 12.04 上的 PHP 从 5.3 升级到 php 5.6

    我正在按照本教程将 php 从版本 5 3 升级到 5 6 http phpave com upgrade php 53 to php 56 on ubuntu 1204 lts http phpave com upgrade php 53
  • 为什么 Orchard 在执行内容项查询时如此慢?

    假设我想查询所有 Orchard 用户 ID 并且还想包括那些已被删除 也称为软删除 的用户 该数据库包含大约 1000 个用户 Option A 大约需要 2 分钟 Orchard ContentManagement IContentMa
  • 将 __DIR__ 常量与字符串连接作为数组值,该数组值是 PHP 中的类成员

    谁能告诉我为什么这不起作用 这只是我在其他地方尝试做的事情的一个粗略的例子 stuff array key gt DIR value 但是 这会产生错误 PHP Parse error syntax error unexpected exp
  • 根据 WooCommerce 中的特定付款方式添加费用

    在 WooCommerce 中 我需要为特定支付网关申请自定义手续费 我这里有这段代码 如何向 WooCommerce Checkout 添加手续费 http www endocreative com add handling fee wo
  • 将文本中的所有 URL 替换为 PHP 中的可点击链接[重复]

    这个问题在这里已经有答案了 我有一个用 PHP 编写的 Web 应用程序 我想找到用户评论中的所有 URL 并将它们更改为可点击的链接 我搜索了很多网站和页面 找到了以下解决方案 不幸的是我没有再次找到它的参考链接 感谢其作者 该代码可以完
  • 显示多个表的账户余额

    我有以下两个表 其中存储有关贷记和借记记录的信息 couponCr 表包含 voucherType voucherPrefix voucherNo crparty cramount SALES S 1 1 43000 SALES S 2 1
  • PHP:检查任何基于拉丁语的语言中的字母字符?

    使用 PHP 我想检查一个字符串仅包含字母字符 我不想允许任何数字或特殊字符 例如 ctype alpha 对于这个目的来说似乎很棒 问题是我想允许重音字母 例如法语等 例如 我想允许 L rien 我知道ctype alpha 可以与se
  • PHP写入文件时,如何使用现有文本在文件前面添加和追加文本?

    我正在使用 PHP 创建一个 xml 文件 这里有一些示例代码 myFile example file xml fh fopen myFile w while row mysql fetch array result stringData
  • 修复 PHP 中格式错误的 HTML?

    我正在根据用户提供的片段构建一个大型 HTML 文档 这些用户有以各种方式格式错误的烦人习惯 浏览器足够强大且宽容 但我希望能够验证并 理想情况下 修复任何格式错误的 HTML 如果可能的话 例如 td b Title b td 可以合理地
  • 当列的数据类型为 int 时,如何用字符串替换 null

    我有一个包含 3 列的表和如下示例数据 所有列都是数据类型int 我有这个查询 select foodid dayid from Schedule 我要更换dayid用字符串 ifdayid null 为此我尝试了这个查询 select f
  • SQL Not Empty 代替 Not NULL

    我正在使用 postgreSQL 我有一个专栏 NOT NULL 但是 当我想插入带有空字符串的行时 如下所示 它不会给我错误并接受 我如何检查插入值应该是not empty 既不为空也不为空 PS 我的专栏定义为 ads characte
  • 如何捕获生成器抛出的异常并恢复迭代?

    我有一个生成器 它将值的集合传递给方法并生成结果 调用的方法可能会返回异常 发生这种情况时 我希望异常转到调用生成器来处理异常的代码 然后继续循环生成器 为了说明这一点 下面是一个生成器的示例 它将产生1 抛出一个 Exception 然后
  • 附加之前检查数据库中是否存在 ID

    我通过选择一个带有类别的数组json decode并将它们附加到文章中 public static function setArticleCategory Request request article Article where id r
  • 如何重命名 SQL Server 中名称中带有方括号的内容?

    我的一张桌子上有一列 周围有方括号 Book Category 我想重命名为Book Category 我尝试了以下查询 sp rename BookPublisher Book Category Book Category COLUMN

随机推荐

  • css设置渐变色

    css如何设置自定义渐变色 线性渐变篇 CSS渐变可以让你在两个或多个指定颜色之间显示平滑的过渡 CSS定义了三种渐变类型 Linear Gradients goes down up left right diagonally 下降 上升
  • python+django基于hadoop大数据的学习资源推送系统的设计与实现vue

    考虑到实际生活中在学习资源推送管理方面的需要以及对该系统认真的分析 将系统按权限进行划分 管理员登入使用本系统涉到的功能主要有个人中心 用户管理 学习视频管理 学习类型管理 系统管理等功能 管理员用例如图3 1所示 图3 1 管理员用例图
  • springboot+jsp高校大学生心理咨询系统

    1 课题目的及意义 随着全球化的发展 各国对高等素质的人才需求越来越大 培养高素质的人才 顺应世界的需求 就要求高校培养的不单单是德智体美劳德人才 还需要心理健康的人才 加强大学生心理素质教育是时代发展的需要 也是中国高等教育改革的需要 近
  • 基于java的可视化高校学生宿舍公寓管理系统springboot+vue

    实现了用户在线选择试题并完成答题 在线查看考核分数 管理员管理班级管理 每日打卡管理 字典管理 访客管理 宿舍缴费记录管理 离校登记管理 宿舍管理 宿舍管理员管理 物品进出登记管理 学生管理 住宿信息管理 管理员管理等功能 管理员功能 1
  • 单个 epoll + 线程池与每个线程一个 epoll 这两种架构哪个更适合大量短连接的场景?

    本文是回答一位知友的提问 单个 epoll 线程池与每个线程一个 epoll 这两种架构哪个更适合大量短连接的场景 不少教程上都提到线程池适合大量的网络短连接的任务场景 但我总感觉这个优势有点站不住脚 单 epoll 线程池模型 主要考虑到
  • 如何系统学习 MySQL?

    一 不建议这么学数据库 首先你要消除一个错误认知 即 如果你想系统地掌握数据库常用的知识点 一定不要以网上各种散乱的文章为重点学习材料 理由有二 网上的资料碎片化比较严重 对于新人来说 可能会造成盲人摸象的感觉 无法形成这块成体系的技术认知
  • nodejs+Vue+elementUI选校园招聘求职网站系统zr299

    从技术实现来讲 可以分为前端技术和后端技术 1 前端技术主要使用vue框架 使用vantUI elementUI搭建前端页面 页面精美 方便快速 2 后端主要使用nodejs 前端通过使用ajax调用接口 进行数据交互 服务器端 数据的存储
  • nodejs+vue+elementui付费自习室座位选座系统-高校教室管理系统nl1u1

    开发语言 node js 框架 Express 技术栈 nodejs vue elementui express 数据库 mysql 数据库工具 Navicat 二 研究方法 1 文献研究法 通过各个文献查找网站 学校图书馆以及百度百科查询
  • python基于django的在线教育学习网站n5138

    在开发系统的过程中 本人运用到vue技术和平时学习中所了解的一些技术 通过实现这些技术 大大提高了整个系统的性能 在论文中这些技术都做了比较详细的介绍 本系统还存在很多缺点和不完善的地方 例如有些细节上做的还不够完善 有些功能模块还需要加强
  • 学习C++,应该循序渐进的看哪些书?

    C C 这门语言与其他高级语言不同 它是离操作系统较近的语言 所以学好 C C 体系的技术栈必须结合操作系统的运行机制来学习 展开来说 就是你必须掌握操作系统层面的几大基础知识 他们是汇编 编译链接与运行时体系 狭义的操作系统原理 多线程
  • socket 编程到底该怎么学?

    通俗地说就是套接字编程 就是使用操作系统提供的一种叫 套接字 的东西 让相同或者不同的机器上的不同进程可以通过网络交互数据 我建议你这么学 一 学习方法与内容 1 计算机网络理论知识 你需要掌握基础的如三次握手和四次挥手的过程以及各个状态值
  • java基于springboot+vue连锁干洗店洗衣店管理系统 含商家

    本课题按照系统角色分为管理员 商家和用户三类用户 系统研究的主要功能模块如下 1 商家角色的主要功能如下 1 后台用户信息管理 管理内部员工信息 对员工信息进行增删改查 设置权限 2 首页咨询 后台录入咨询 在首页进行资讯模块展示 用户可以
  • nodejs基于vue的视频分享投稿商城播放系统617bx

    本视频播放系统的设计目标是为用户提供一个便利的视频播放平台 同时系统融入投稿 商城以及论坛等功能模块 更全面的为用户提供服务 本文重点阐述了视频播放系统的开发过程 以实际运用为开发背景 基于vue框架 B S结构 运用了nodejs技术和M
  • springboot+vue+elementui大学生心理健康咨询测试网站_4u6b7

    本基于Java的大学生心理健康网站是根据当前我国大学生的心理相关的内容实际情况开发的 在系统语言选择上我们使用的Java语言 数据库是小巧灵活的MySQL数据库 本系统的开发可以极大的提高大学生心理健康方面的管理 本基于Java的大学生心理
  • 校招C++大概学习到什么程度?

    一图胜千言 C C 这门语言与其他高级语言不同 它是离操作系统较近的语言 所以学好 C C 体系的技术栈必须结合操作系统的运行机制来学习 展开来说 就是你必须掌握操作系统层面的几大基础知识 他们是汇编 编译链接与运行时体系 狭义的操作系统原
  • python基于django毕业生跟踪调查反馈系统pycharm毕业设计推荐

    通过该设计能够综合运用和深化理解所学理论知识 熟练基本技能 提高调查研究 收集资料以及分析和解决实际问题的能力 运用自顶向下逐层分解的模块化结构设计思想 面向对象的设计方法 完成面向工程教育专业认证的毕业生跟踪调查反馈系统的设计与实现 系统
  • pycharm+python物流配送管理系统221y2

    预期达到的目标 1 学习系统开发和设计的技术相关知识和工作流程 2 学习使用pycharm 工具编辑前后台代码 3 学习使用djnago框架实现系统的开发 4 掌握使用 MySQL 创建和编辑数据库的方法 本课题使用Python语言进行开发
  • 基于java的KTV包厢管理系统springboot+vue

    KTV包厢管理系统经过分析 确定了其需要设置用户的角色 其操作的功能通过用例图展示 见下图 用户预订包间 购买商品 发布留言反馈信息 查看优惠资讯 不同的系统提供的服务也不相同 其对应的功能也不相同 所以 系统开工前 需要明确其用途 确定其
  • 基于Java的数据结构精品课程教学网站

    收藏关注不迷路 源码文章末 文章目录 前言 一 项目介绍 二 开发环境 三 功能介绍 四 核心代码 五 效果图 六 文章目录 前言 本基于Java的数据结构精品课程教学网站是根据当前教学大环境相关的内容实际情况开发的 在系统语言选择上我们使
  • 使用epoll时需要将socket设为非阻塞吗?

    本文是回答一位知友的提问 在APUE中介绍select和poll中说 一个描述阻塞与否并不影响select是否阻塞 也就是说 如果希望读一个非阻塞描述符 并且以超时值5s调用select 则select最多阻塞5s 我看到有些程序使用epo