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

IO多路复用的三种实现:select

select

 int select(int nfds, fd_set * readfds, fd_set* writefds, fd_set* exceptfds, struct timeval* timeout);

功能:多路IO复用。

参数:

 nfds: readfsd\ writefds\exceptfds三个位图中使用的最大的文件描述符号+1.

 readfds: 位图(128Byte,1024bit),需要监听的读事件集合

 writefds: 位图(128Byte,1024bit),需要监听的写事件集合

exceptfds: 位图(128Byte,1024bit),需要监听的异常事件集合

 timeout:超时时长,传NULL:如果没有监听的事件没有发生,就一直阻塞等待;传非0:表示超时时间,在规定的时间内如果监听的时间都没有发生,select 返回0;传0:表示非阻塞。调用的时候查看一遍监听集合,如果没有任何事件发生,select立即返回0。

返回值:

-1,出错并设置errno;0:表示没有任何监听的事发生;>0:监听的三个集合发生的事件和。

优点:

跨平台,开销小。

缺点:

受限数据结构的限制,能够监听的文件描述符上限1024个。

轮询监听机制,在活跃用户量小的时候监听效率比较低。

大量的用户和内核空间的数据拷贝。

利用select单进程实现多可客户端连接的服务器代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>                                                              
#include<unistd.h>
#include<errno.h>
#include<pthread.h>
#include<sys/wait.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<fcntl.h>
#include<arpa/inet.h>
#include<sys/select.h>
#define SERPORT 8000
#define SERIP "IP地址"


int main(int argc, char* argv[])
{
    int lfd = socket(AF_INET,SOCK_STREAM,0);

    struct sockaddr_in seraddr,cliaddr;
    seraddr.sin_family = AF_INET;
    seraddr.sin_port = htons(SERPORT);
    int dst;
    inet_pton(AF_INET,SERIP,(void*)&dst);
    seraddr.sin_addr.s_addr = dst;

    int ret = bind(lfd,(struct sockaddr*)&seraddr,sizeof(seraddr));
    listen(lfd,64);

    socklen_t addrlen = sizeof(cliaddr);

    char buf[1024];
    int maxfd;
    fd_set rset, aset;
    FD_ZERO(&aset);
    FD_SET(lfd,&aset);
    maxfd = lfd;
    int i = 0;
    int cfd;
    char clip[32];
    while(1){
        rset = aset;
        int sret = select(maxfd + 1, &rset, NULL, NULL, NULL);
        if(sret<0){
            perror("select error");
            exit(1);
        }
        if(FD_ISSET(lfd, &rset)){
            cfd = accept(lfd,(struct sockaddr*)&cliaddr,&addrlen);
            if(cfd<0){
                perror("accept error");
                exit(1);
            }
            //网络字节序整形IP地址转化成一个本地字节序点分十进制的字符窜IP
            inet_ntop(AF_INET,&cliaddr.sin_addr,clip,sizeof(clip));
            printf("clien IP=%s,PORT=%d connect ok\n",clip,ntohs(cliaddr.sin_port));
            FD_SET(cfd, &aset);
            if(cfd>maxfd){
                maxfd = cfd;
            }
            if(--sret ==0 ){
                continue;
            }
        }
        for(i = lfd+1;i<maxfd+1;i++){
            if(FD_ISSET(i, &rset)){
            int rr = read(i,buf,sizeof(buf));
            if(rr < 0){
                perror("read error");
                exit(1);
            }
            else if(rr == 0){
                //客户端断开连接
                FD_CLR(i, &aset);
                close(i);
                printf("客户端断开连接\n");
            }
            write(STDOUT_FILENO,buf,rr);
            write(i,buf,rr);
            if(--sret == 0){
                break;
            }
         }
      }
     }   
    return 0;
}


http://www.kler.cn/a/4084.html

相关文章:

  • 基于Python+Gurobi的库存分配问题建模求解
  • .NET 学习:从基础到进阶的全面指南
  • PCL 新增自定义点类型【2025最新版】
  • Power Automate 实现字符串分割、替换、换行显示
  • 51.WPF应用加图标指南 C#例子 WPF例子
  • python管理工具:conda部署+使用
  • 企业电子招标采购源码之电子招标投标全流程!
  • 社科院与杜兰大学金融管理硕士项目,承载着你读研时光的喜与乐
  • 前端CI篇—重生之前端已死转行运维
  • qt发布程序后在其他电脑无法连接mysql数据库的解决方案
  • Spring源码分析-Bean创建流程三
  • webpack 配置介绍
  • 不再空谈,用 InsCode 展示你的编程实力
  • (QT)常用快捷键与代码风格学习
  • web js代码作业
  • 访问 linux/ubuntu 共享文件夹失败 (及共享文件夹配置)
  • C语言实现栈和队列(动态)
  • [Ubuntu][网络][教程]端口转发以及端口管理
  • 【前推回代法】含有分布式电源的三相不平衡配电网潮流计算【IEEE33节点】(Matlab代码实现)
  • 数据库总结笔记
  • 第三章:Linux环境基础开发工具使用
  • 【云原生】容器编排技术Docker Compose
  • R语言 使用bnlearn包中的数据集
  • 多个sheet Excel 数据 导入数据库 如何实现?
  • 世界棒球经典赛:大谷翔平击败美国队,日本队第三次夺冠
  • 【Stable Diffusion】windows 1050显卡,17年笔记本还能再战