0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Linux--IO多路复用(select,poll,epoll)

Rice嵌入式开发技术分享 2024-11-06 16:13 次阅读

IO多路复用——select,poll,epoll

IO多路复用是一种操作系统技术,旨在提高系统处理多个输入输出操作的性能和资源利用率。与传统的多线程或多进程模型相比,IO多路复用避免了因阻塞IO而导致的资源浪费和低效率问题。它通过将多个IO操作合并到一个系统调用中,允许程序同时等待多个文件描述符(如sockets、文件句柄等)变为可读或可写状态,然后再执行实际的IO操作。

在IO多路复用的实现中,常用的系统调用包括select()poll()epoll()。这些机制允许程序监视多个描述符,一旦某个描述符就绪(通常是读就绪或写就绪),程序就会被通知进行相应的读写操作。这个过程通常涉及两个阶段:

  1. 等待数据到达:程序等待数据从IO设备传输到内核空间。在这个阶段,IO多路复用的系统调用会阻塞,直到至少有一个描述符准备好进行IO操作。
  2. 数据复制:当一个或多个描述符就绪时,程序负责将数据从内核空间复制到用户空间(进程或线程的缓冲区)。这第二个阶段是实际的读写操作,它在IO多路复用的上下文中是同步的,因为程序需要自己执行数据的读写。

尽管select()poll()epoll()都是同步IO操作,但它们提供了一种有效的方式来处理并发IO,降低了系统开销,并提高了并发处理能力。与此不同,异步IO(AIO)模型进一步简化了IO操作,因为它允许操作系统自动处理数据从内核到用户空间的复制过程,无需程序显式调用读写操作。这意味着在异步IO模型中,读写操作由操作系统在后台完成,从而进一步提高了应用程序的效率和响应性。

select

概述

  • 系统提供了select函数来实现多路复用输入/输出模型
  • select系统调用是用来让我们的程序监视多个文件描述符的状态变化的
  • 程序会停在select函数等待,直到被监视的文件描述符有一个或者多个发生了状态改变。

函数

intselect(intnfds,fd_set*readfds,fd_set*writefds,
fd_set*exceptfds,structtimeval*timeout)
;
  • 函数参数:
参数说明
nfds是需要监视的最大的文件描述符值+1
readfds需要检测的可读文件描述符的集合
writefds需要检测的可写文件描述符的集合
exceptfds需要检测的异常文件描述符的集合
timeout当timeout等于NULL:则表示select()没有timeout,select将一直被阻塞,直到某个文件描述符上发生了事件;
当timeout为0:仅检测描述符集合的状态,然后立即返回,并不等待外部事件的发生。
当timeout为特定的时间值:如果在指定的时间段里没有事件发生,select将超时返回。
返回——
> 0返回文件描述词状态已改变的个数
== 0代表在描述词状态改变前已超过timeout时间,没有返回
< 0错误原因存于errno,此时参数readfds,writefds, exceptfds和timeout的值变成不可预测,错误值可能为:
EBADF:文件描述词为无效的或该文件已关闭
EINTR:此调用被信号所中断
EINVAL:参数n 为负值
ENOMEM:核心内存不足
  • 其中:可读,可写,异常文件描述符的集合是一个fd_set类型,fd_set是系统提供的位图类型,位图的位置是否是1,表示是否关系该事件。例如:
输入时:假如我们要关心0123文件描述符
00000000->00001111比特位的位置,表示文件描述符的编号
比特位的内容0or1表示是否需要内核关心
输出时:
00000100->此时表示文件描述符的编号
比特位的内容0or1哪些用户关心的fd上面的读事件已经就绪了,这里表示2描述符就绪了
  • 系统提供了关于fd_set的接口,便于我们使用位图:
voidFD_CLR(intfd,fd_set*set);//用来清除描述词组set中相关fd的位
intFD_ISSET(intfd,fd_set*set);//用来测试描述词组set中相关fd的位是否为真
voidFD_SET(intfd,fd_set*set);//用来设置描述词组set中相关fd的位
voidFD_ZERO(fd_set*set);//用来清除描述词组set的全部位

执行流程:

  1. 执行fd_set set; FD_ZERO(&set);则set用位表示是0000,0000。
  2. 若fd=5,执行FD_SET(fd,&set);后set变为0001,0000(第5位置为1) 。
  3. 若再加入fd=2,fd=1,则set变为0001,0011 。
  4. 执行select(6,&set,0,0,0)阻塞等待,表示最大文件描述符+1是6,监控可读事件,立即返回。
  5. 若fd=1,fd=2上都发生可读事件,则select返回,此时set变为0000,0011。注意:没有事件发生的fd=5被清空。

优缺点

  • 优点:
  1. 可监控的文件描述符个数取决与sizeof(fd_set)的值。一般大小是1024,但是fd_set的大小可以调整。
  2. 将fd加入select监控集的同时,还要再使用一个数据结构array保存放到select监控集中的fd。①是用于再select 返回后,array作为源数据和fd_set进行FD_ISSET判断。②是select返回后会把以前加入的但并无事件发生的fd清空,则每次开始select前都要重新从array取得fd逐一加入(FD_ZERO最先),扫描array的同时取得fd最大值maxfd,用于select的第一个参数。
  • 缺点:
    1. 每次调用select, 都需要手动设置fd集合, 从接口使用角度来说也非常不便。
    2. 每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大。
    3. 同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大。
    4. select支持的文件描述符数量太小。

    实例

    #include
    #include
    #include
    #include
    #include
    #include

    conststaticintMAXLINE=1024;
    conststaticintSERV_PORT=10001;

    intmain()
    {
    inti,maxi,maxfd,listenfd,connfd,sockfd;
    /*nready描述字的数量*/
    intnready,client[FD_SETSIZE];
    intn;
    /*创建描述字集合,由于select函数会把未有事件发生的描述字清零,所以我们设置两个集合*/
    fd_setrset,allset;
    charbuf[MAXLINE];
    socklen_tclilen;
    structsockaddr_incliaddr,servaddr;
    /*创建socket*/
    listenfd=socket(AF_INET,SOCK_STREAM,0);
    /*定义sockaddr_in*/
    memset(&servaddr,0,sizeof(servaddr));
    servaddr.sin_family=AF_INET;
    servaddr.sin_port=htons(SERV_PORT);
    servaddr.sin_addr.s_addr=htonl(INADDR_ANY);

    bind(listenfd,(structsockaddr*)&servaddr,sizeof(servaddr));
    listen(listenfd,100);
    /*listenfd是第一个描述字*/
    /*最大的描述字,用于select函数的第一个参数*/
    maxfd=listenfd;
    /*client的数量,用于轮询*/
    maxi=-1;
    /*init*/
    for(i=0;iclient[i]=-1;
    FD_ZERO(&allset);
    FD_SET(listenfd,&allset);

    for(;;)
    {
    rset=allset;
    /*只select出用于读的描述字,阻塞无timeout*/
    nready=select(maxfd+1,&rset,NULL,NULL,NULL);
    if(FD_ISSET(listenfd,&rset))
    {
    clilen=sizeof(cliaddr);
    connfd=accept(listenfd,(structsockaddr*)&cliaddr,&clilen);
    /*寻找第一个能放置新的描述字的位置*/
    for(i=0;i{
    if(client[i]<0)
    {
    client[i]=connfd;
    break;
    }
    }
    /*找不到,说明client已经满了*/
    if(i==FD_SETSIZE)
    {
    printf("Toomanyclients,overstack.\n");
    return-1;
    }
    FD_SET(connfd,&allset);//设置fd
    /*更新相关参数*/
    if(connfd>maxfd)maxfd=connfd;
    if(i>maxi)maxi=i;
    if(nready<=1)continue;
    elsenready--;
    }

    for(i=0;i<=maxi ; i++)
    {
    if(client[i]<0)continue;
    sockfd=client[i];
    if(FD_ISSET(sockfd,&rset))
    {
    n=read(sockfd,buf,MAXLINE);
    if(n==0)
    {
    /*当对方关闭的时候,server关闭描述字,并将set的sockfd清空*/
    close(sockfd);
    FD_CLR(sockfd,&allset);
    client[i]=-1;
    }
    else
    {
    buf[n]='\0';
    printf("Socket%dsaid:%s\n",sockfd,buf);
    write(sockfd,buf,n);//Writebacktoclient
    }
    nready--;
    if(nready<=0)break;
    }
    }

    }
    return0;
    }

    poll

    概述

    • poll和select实现原理基本类似
    • poll只为了解决select的两个硬伤:①等待的fd是有上限的,(底层类似链表储存实现,而不是位图)。②每次要对关心的fd进行事件重置,(pollfd结构包含了要监视的event和发生的event,使用前后不用初始化fd_set)。

    函数

    intpoll(structpollfd*fds,nfds_tnfds,inttimeout);

    //pollfd结构
    structpollfd{
    intfd;/*filedescriptor*/
    shortevents;/*requestedevents*/
    shortrevents;/*returnedevents*/
    };
    • 函数参数:
    参数说明
    fds是一个poll函数监听的结构列表. 每一个元素中, 包含了三部分内容: 文件描述符, 监听的事件集合, 返回的事件集合
    nfds表示fds数组的长度
    timeout表示poll函数的超时时间, 单位是毫秒(ms)
    返回——
    > 0表示poll由于监听的文件描述符就绪而返回
    == 0表示poll函数等待超时
    < 0表示出错

    优缺点

    • 优点:
    1. pollfd结构包含了要监视的event和发生的event,不再使用select“参数-值”传递的方式. 接口使用比 select更方便。
    2. poll并没有最大数量限制 (但是数量过大后性能也是会下降)。
  • 缺点:
    1. 和select函数一样,poll返回后,需要轮询pollfd来获取就绪的描述符。
    2. 每次调用poll都需要把大量的pollfd结构从用户态拷贝到内核中。
    3. 同时连接的大量客户端在一时刻可能只有很少的处于就绪状态, 因此随着监视的描述符数量的增长, 其效率也会线性下降。

    实例

    #include
    #include
    #include
    #include
    #include
    #include

    #defineMAXLINE1024
    #defineOPEN_MAX16//一些系统会定义这些宏
    #defineSERV_PORT10001

    intmain()
    {
    inti,maxi,listenfd,connfd,sockfd;
    intnready;
    intn;
    charbuf[MAXLINE];
    socklen_tclilen;
    structpollfdclient[OPEN_MAX];

    structsockaddr_incliaddr,servaddr;
    listenfd=socket(AF_INET,SOCK_STREAM,0);
    memset(&servaddr,0,sizeof(servaddr));
    servaddr.sin_family=AF_INET;
    servaddr.sin_port=htons(SERV_PORT);
    servaddr.sin_addr.s_addr=htonl(INADDR_ANY);

    bind(listenfd,(structsockaddr*)&servaddr,sizeof(servaddr));
    listen(listenfd,10);
    client[0].fd=listenfd;
    client[0].events=POLLRDNORM;
    for(i=1;i{
    client[i].fd=-1;
    }
    maxi=0;

    for(;;)
    {
    nready=poll(client,maxi+1,INFTIM);
    if(client[0].revents&POLLRDNORM)
    {
    clilen=sizeof(cliaddr);
    connfd=accept(listenfd,(structsockaddr*)&cliaddr,&clilen);
    for(i=1;i{
    if(client[i].fd<0)
    {
    client[i].fd=connfd;
    client[i].events=POLLRDNORM;
    break;
    }
    }
    if(i==OPEN_MAX)
    {
    printf("toomanyclients!\n");
    }
    if(i>maxi)maxi=i;
    nready--;
    if(nready<=0)continue;
    }

    for(i=1;i<=maxi;i++)
    {
    if(client[i].fd<0)continue;
    sockfd=client[i].fd;
    if(client[i].revents&(POLLRDNORM|POLLERR))
    {
    n=read(client[i].fd,buf,MAXLINE);
    if(n<=0)
    {
    close(client[i].fd);
    client[i].fd=-1;
    }
    else
    {
    buf[n]='\0';
    printf("Socket%dsaid:%s\n",sockfd,buf);
    write(sockfd,buf,n);//Writebacktoclient
    }
    nready--;
    if(nready<=0)break;//nomorereadabledescriptors
    }
    }
    }
    return0;
    }

    epoll

    概述

    • epoll:是为处理大批量句柄而作了改进的poll(真的是大改进)
    • epoll是IO多路复用技术,在实现上维护了一个用于返回触发事件的Socket的链表和一个记录监听事件的红黑树,epoll的高效体现在:
    1. 对监听事件的修改是 logN(红黑树)。
    2. 用户程序无需遍历所有的Socket(发生事件的Socket被放到链表中直接返回)。
    3. 内核无需遍历所有的套接字,内核使用回调函数在事件发生时直接转到对应的处理函数。

    函数

    • epoll_create:创建一个epoll的句柄,用完之后, 必须调用close()关闭。
    intepoll_create(intsize);
    • epoll_ctl:它不同于select()是在监听事件时告诉内核要监听什么类型的事件, 而是在这里先注册要监听的事件类型。
    intepoll_ctl(intepfd,intop,intfd,structepoll_event*event);

    typedefunionepoll_data
    {
    void*ptr;
    intfd;
    uint32_tu32;
    uint64_tu64;
    }epoll_data_t;

    structepoll_event
    {

    uint32_tevents;
    epoll_data_tdata;
    }EPOLL_PACKED;
    1. events参数的宏集合:
    EPOLLIN :表示对应的文件描述符可以读(包括对端SOCKET正常关闭)。
    EPOLLOUT :表示对应的文件描述符可以写。
    EPOLLPRI :表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来)。
    EPOLLERR :表示对应的文件描述符发生错误。
    EPOLLHUP :表示对应的文件描述符被挂断。
    EPOLLET :将EPOLL设为边缘触发(Edge Triggered)模式, 这是相对于水平触发(Level Triggered)来说的。
    EPOLLONESHOT:只监听一次事件, 当监听完这次事件之后, 如果还需要继续监听这个socket的话, 需要再次把这个socket加入到EPOLL队列里
    1. 函数参数:
    参数说明
    epfdepoll_create()的返回值(epoll的句柄)
    op表示动作,用三个宏来表示:
    EPOLL_CTL_ADD :注册新的fd到epfd中
    EPOLL_CTL_MOD :修改已经注册的fd的监听事件
    EPOLL_CTL_DEL :从epfd中删除一个fd
    fd需要监听的fd
    event内核需要监听的事件
    • epoll_wait:收集在epoll监控的事件中已经发送的事件
    intepoll_wait(intepfd,structepoll_event*events,intmaxevents,inttimeout);
    参数说明
    epfdepoll_create()的返回值(epoll的句柄)
    events是分配好的epoll_event结构体数组。epoll将会把发生的事件赋值到events数组中 (events不可以是空指针,内核只负责把数据复制到这个events数组中,不会去帮助我们在用户态中分配内存)
    maxevents通知内核这个events有多大,这个maxevents的值不能大于创建epoll_create()时的size
    timeout超时时间 (毫秒,0会立即返回,-1是永久阻塞)
    返回——
    > 0返回对应I/O上已准备好的文件描述符数目
    == 0表示已超时
    < 0表示失败

    执行流程:

    1. 当某一进程调用epoll_create方法时,Linux内核会创建一个eventpoll结构体,这个结构体中有两个成员与epoll的使用方式密切相关。
    2. 每一个epoll对象都有一个独立的eventpoll结构体,用于存放通过epoll_ctl方法向epoll对象中添加进来的事件。
    3. 这些事件都会挂载在红黑树中,如此,重复添加的事件就可以通过红黑树而高效的识别出来(红黑树的插入时间效率是lgn,其中n为树的高度)。
    4. 而所有添加到epoll中的事件都会与设备(网卡)驱动程序建立回调关系,也就是说,当响应的事件发生时会调用这个回调方法。
    5. 这个回调方法在内核中叫ep_poll_callback,它会将发生的事件添加到rdlist双链表中。
    6. 在epoll中,对于每一个事件,都会建立一个epitem结构体。
    7. 当调用epoll_wait检查是否有事件发生时,只需要检查eventpoll对象中的rdlist双链表中是否有epitem元素即可。
    8. 如果rdlist不为空,则把发生的事件复制到用户态,同时将事件数量返回给用户. 这个操作的时间复杂度是O(1)。

    优缺点

    • 优点:
    1. 接口使用方便: 虽然拆分成了三个函数,但是反而使用起来更方便高效,不需要每次循环都设置关注的文件描述符,也做到了输入输出参数分离开。
    2. 数据拷贝轻量: 只在合适的时候调用 EPOLL_CTL_ADD 将文件描述符结构拷贝到内核中,这个操作并不频繁(而select/poll都是每次循环都要进行拷贝)。
    3. 事件回调机制: 避免使用遍历,而是使用回调函数的方式,将就绪的文件描述符结构加入到就绪队列中,epoll_wait 返回直接访问就绪队列就知道哪些文件描述符就绪,这个操作时间复杂度O(1),即使文件描述符数目很多,效率也不会受到影响。
    4. 没有数量限制: 文件描述符数目无上限。
  • 缺点:
    1. 不能跨平台,epoll 是 Linux 特有的 API,不太容易移植到其他操作系统上

    实例

    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include

    #defineMAXLINE1024
    #defineOPEN_MAX16//一些系统会定义这些宏
    #defineSERV_PORT10001

    intmain()
    {
    inti,maxi,listenfd,connfd,sockfd,epfd,nfds;
    intn;
    charbuf[MAXLINE];
    structepoll_eventev,events[20];
    socklen_tclilen;
    structpollfdclient[OPEN_MAX];

    structsockaddr_incliaddr,servaddr;
    listenfd=socket(AF_INET,SOCK_STREAM,0);
    memset(&servaddr,0,sizeof(servaddr));
    servaddr.sin_family=AF_INET;
    servaddr.sin_port=htons(SERV_PORT);
    servaddr.sin_addr.s_addr=htonl(INADDR_ANY);

    bind(listenfd,(structsockaddr*)&servaddr,sizeof(servaddr));
    listen(listenfd,10);

    epfd=epoll_create(256);
    ev.data.fd=listenfd;
    ev.events=EPOLLIN|EPOLLET;
    epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev);

    for(;;)
    {
    nfds=epoll_wait(epfd,events,20,500);
    for(i=0;i{
    if(listenfd==events[i].data.fd)
    {
    clilen=sizeof(cliaddr);
    connfd=accept(listenfd,(structsockaddr*)&cliaddr,&clilen);
    if(connfd< 0)
    {
    perror("connfd< 0");
    exit(1);
    }
    ev.data.fd=connfd;
    ev.events=EPOLLIN|EPOLLET;
    epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev);
    }
    elseif(events[i].events&EPOLLIN)
    {
    if((sockfd=events[i].data.fd)< 0)
    continue;
    n=recv(sockfd,buf,MAXLINE,0);
    if(n<= 0)
    {
    close(sockfd);
    events[i].data.fd=-1;
    }
    else
    {
    buf[n]='\0';
    printf("Socket%dsaid:%s\n",sockfd,buf);
    ev.data.fd=sockfd;
    ev.events=EPOLLOUT|EPOLLET;
    epoll_ctl(epfd,EPOLL_CTL_MOD,connfd,&ev);
    }
    }
    elseif(events[i].events&EPOLLOUT)
    {
    sockfd=events[i].data.fd;
    send(sockfd,"Hello!",7,0);

    ev.data.fd=sockfd;
    ev.events=EPOLLIN|EPOLLET;
    epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);
    }
    else
    {
    printf("Thisisnotavaible!");
    }
    }
    }
    close(epfd);
    return0;
    }

    总结

    • selectpoll 是两种传统的 I/O 多路复用技术,它们允许服务器应用程序同时监控多个网络连接,以便在连接准备就绪时进行读写操作。尽管这两种技术在处理大量并发连接时非常有用,但随着连接数的增加,它们的性能会逐渐下降,因为它们需要在每次调用时遍历整个文件描述符集合,这在连接数非常多时会导致效率问题。

    • 为了解决这个问题,epoll 作为 selectpoll 的一种改进方案,在 Linux 系统中被引入。epoll 提供了一种更为高效的事件驱动模型,它可以显著提高处理大量并发连接的性能。与 selectpoll 不同,epoll 不会对整个文件描述符集合进行线性遍历,而是使用一组特殊的数据结构来跟踪哪些文件描述符已经准备好 I/O 操作。这种机制使得 epoll 能够快速地通知应用程序哪些连接是活跃的,而无需对所有连接进行不必要的检查。

    • epoll 的另一个优点是它能够处理大量文件描述符而不会显著增加资源消耗,这使得它非常适合需要处理成千上万甚至更多并发连接的高性能网络服务器。因此,在 Linux 系统上,epoll 常被视为 selectpoll 的替代方案,特别是在构建高性能网络应用程序时。

    - END -


    往期推荐:点击图片即可跳转阅读



    linux--sysfs文件系统



    YY3568 Debian11+RT-Thread混合内核部署



    YY3568多核异构(Linux+RT-Thread)--启动流程




    原文标题:Linux--IO多路复用(select,poll,epoll)

    文章出处:【微信公众号:Rice 嵌入式开发技术分享】欢迎添加关注!文章转载请注明出处。

    声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
    收藏 人收藏

      评论

      相关推荐

      多路复用模拟输入应用中使用ADS8411

      电子发烧友网站提供《在多路复用模拟输入应用中使用ADS8411.pdf》资料免费下载
      发表于 10-22 09:32 0次下载
      在<b class='flag-5'>多路复用</b>模拟输入应用中使用ADS8411

      AM17xx引脚多路复用实用程序

      电子发烧友网站提供《AM17xx引脚多路复用实用程序.pdf》资料免费下载
      发表于 10-14 10:22 0次下载
      AM17xx引脚<b class='flag-5'>多路复用</b>实用程序

      多路复用器应用中的防护

      电子发烧友网站提供《多路复用器应用中的防护.pdf》资料免费下载
      发表于 09-21 10:47 0次下载
      <b class='flag-5'>多路复用</b>器应用中的防护

      基于带宽的无源多路复用器>Ron

      电子发烧友网站提供《基于带宽的无源多路复用器>Ron.pdf》资料免费下载
      发表于 09-21 10:46 0次下载
      基于带宽的无源<b class='flag-5'>多路复用</b>器>Ron

      电源多路复用器基础知识

      电子发烧友网站提供《电源多路复用器基础知识.pdf》资料免费下载
      发表于 09-21 10:21 0次下载
      电源<b class='flag-5'>多路复用</b>器基础知识

      如何使用多路复用器处理高压共模应用

      电子发烧友网站提供《如何使用多路复用器处理高压共模应用.pdf》资料免费下载
      发表于 09-11 11:34 0次下载
      如何使用<b class='flag-5'>多路复用</b>器处理高压共模应用

      多路复用器将取代继电器应用说明

      电子发烧友网站提供《多路复用器将取代继电器应用说明.pdf》资料免费下载
      发表于 09-11 10:05 0次下载
      <b class='flag-5'>多路复用</b>器将取代继电器应用说明

      电源多路复用器电路设计指南

      电子发烧友网站提供《电源多路复用器电路设计指南.pdf》资料免费下载
      发表于 07-13 09:33 0次下载

      什么是多路复用器?它有哪些作用和应用?

      在现代通信与数据处理领域,多路复用器(Multiplexer,简称MUX)作为一种关键设备,发挥着不可替代的作用。它能够将多个输入信号选择性地合并到一个输出信号中,从而实现了对通信信道的高效利用
      的头像 发表于 05-23 16:38 3651次阅读

      频分多路复用和时分多路复用的区别有哪些

      频分多路复用(FDM)和时分多路复用(TDM)是两种主要的多路复用技术,它们在通信系统中扮演着至关重要的角色。
      的头像 发表于 05-07 15:24 2580次阅读

      多路复用技术主要有几种类型?它们各有什么特点?

      多路复用技术主要有几种类型?它们各有什么特点? 多路复用技术主要有以下几种类型:进程多路复用、I/O多路复用、信号驱动I/O和异步I/O。每种类型都有其特点和应用场景。 1. 进程
      的头像 发表于 03-28 15:36 2859次阅读

      一文详解多路复用的类型

      多路复用最初是在电话中发展起来的。多个信号被组合在一起,通过一根电缆发送。
      的头像 发表于 03-05 15:44 3282次阅读
      一文详解<b class='flag-5'>多路复用</b>的类型

      多路复用的原理 为什么要多路复用多路复用技术的应用

      在计算机网络中,多路复用是一种重要的通信技术,它允许多个信号通过同一个通信信道进行传输。
      的头像 发表于 03-05 15:09 2854次阅读
      <b class='flag-5'>多路复用</b>的原理 为什么要<b class='flag-5'>多路复用</b>?<b class='flag-5'>多路复用</b>技术的应用

      频分多路复用的原理 频分多路复用方式的分类

      频分多路复用(Frequency-division multiplexing,FDM),是指载波带宽被划分为多种不同频带的子信道,每个子信道可以并行传送一路信号的一种多路复用技术。
      的头像 发表于 03-05 14:10 1424次阅读
      频分<b class='flag-5'>多路复用</b>的原理 频分<b class='flag-5'>多路复用</b>方式的分类

      什么是io多路复用IO多路复用的优缺点

      IO多路复用是一种同步IO模型,它允许单个进程/线程同时处理多个IO请求。具体来说,一个进程/线程可以监视多个文件句柄,一旦某个文件句柄就绪,就能够通知应用程序进行相应的读写操作。在没
      的头像 发表于 01-18 15:48 1646次阅读