Linux I/O复用函数的使用情况和select接口的介绍

news2024/12/26 0:02:23

I/O 复用使得程序能同时监听多个文件描述符,这对于提高程序的性能至关重要。通常,
网络程序在下列情况下需要使用 I/O 复用技术:
1.TCP服务器同时要处理监听套接字和连接套接字

2.服务器同时要处理TCP请求和UDP请求。

3.程序同时要处理多个套接字。

4.客服端程序要同时处理用户输入和网络连接。

5.服务器要同时监听多个端口。

        需要指出的是, I/O 复用虽然能同时监听多个文件描述符,但它本身是阻塞的。并且当
多个文件描述符同时就绪时,如果不采取额外的措施,程序就只能按顺序依处理其中的每一
个文件描述符,这使得服务器看起来好像是串行工作的。如果要提高并发处理的能力,可以
配合使用多线程或多进程等编程方法。

1select

1.1select的接口介绍

        select系统调用的用途是:再一段指定时间内,监听用户感兴趣的文件描述符的可读、可写和异常事件。

        select系统调用的原型如下:

# include <sys/select.h>
int select (int maxfd,fd_set*readfds,fd_set*writefds,fd_set*exceptfds,struct timeval*timeout);
/*
select 成功时返回就绪(可读、可写和异常)文件描述符的总数。如果在超时间内没有任何文件描述符就绪,select将返回0.select失败返回-1,如果是在select等待期间,程序接收到信号,则select立即返回-1,并设置errno为EINTR。
maxfd 参数指定的被监听的文件描述符的总数。它通常被设置为 select 监听的所
有文件描述符中的最大值+1
readfds、 writefds 和 exceptfds 参数分别指向可读、可写和异常等事件对应的文件
描述符集合。应用程序调用 select 函数时,通过这 3 个参数传入自己感兴趣的文件
描述符。 select 返回时,内核将修改它们来通知应用程序哪些文件描述符已经就绪
通过下列宏可以访问 fd_set 结构中的位:
FD_ZERO(fd_set *fdset); // 清除 fdset 的所有位
FD_SET(int fd, fd_set *fdset); // 设置 fdset 的位 fd,fd添加到集合(置一)
FD_CLR(int fd, fd_set *fdset); // 清除 fdset 的位 fd
int FD_ISSET(int fd, fd_set *fdset);// 测试 fdset 的位 fd 是否被设置
timeout 参数用来设置 select 函数的超时时间。它是一个 timeval 结构类型的指
针,采用指针参数是因为内核将修改它以告诉应用程序 select 等待了多久。 timeval
结构的定义如下
struct timeval
{
    long tv_sec;//秒数
    long tv_usec://微秒数
};
如果给 timeout 的两个成员都是 0,则 select 将立即返回。如果 timeout 传递
NULL,则 select 将一直阻塞,直到某个文件描述符就绪
*/

         

 1.2select的示例代码

使用select实现的TCP服务器如下:

初始化服务器端的sockfd套接字

int initsocket()
{
    int sockfd=socket(AF_INET,SOCK_STREAM,0);
    if (sockfd==-1)
        return -1;
    struct sockaddr_in saddr;
    memset(&saddr,0,sizeof (saddr));
    saddr.sin_family=AF_INET;
    saddr.sin_port=htons(6000);
    saddr.sin_addr.s_addr=inet_addr("127.0.0.1");
    int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof (saddr));
    if (res==-1)
        return -1;
    res=listen(sockfd,5);
    if (res==-1)
        return -1;
    return sockfd;
}

初始化记录服务器套接字的数组

void initFds(int fds[],int n)
{
    int i=0;
    for (;i<n;i++)
    {
        fds[i]=-1;
    }
}

将套接字描述符添加到数组中

void AddFdToFds(int fds[],int fd,int n)
{   
    int i=0;
    for (;i<n;i++)
    {
        if (fds[i]==-1)
        {
            fds[i]=fd;
            break;
        }
    }
}

删除数组中的套接字描述符

void DelFromFds(int fds[],int fd,int n)
{
    for (int i=0;i<n;i++)
    {
        if (fds[i]==fd)
        {
            fds[i]=-1;
            break;
        }
    }
}

将数组中的套接字描述符设置到fd_set变量中,并返回当前最大文件描述符

int SetFsToFdset(fd_set*fdset,int fds[],int n)
{
    FD_ZERO(fdest);//fdest置零
    int i=0;
    int maxfd=fds[0];//最大文件描述符的值
    for (;i<n;i++)
    {
        if (fds[i]!=-1)
        {
            FD_SET(fds[i],fdest);//将fdest的位fds[i]的值置为1
            if (fds[i]>maxfd)
            {
                maxfd=fds[i];
            }
        }
    }
    return maxfd;
}

服务器和客户端的连接

void GetClientLink(int sockfd,int fds[],int n)
{    
    struct sockaddr_in caddr;
    int len=sizeof (caddr);
    memset(&caddr,0,sizeof(caddr));
    int c=accept(sockfd,(struct sockaddr*)&caddr,&len);
    if (c<0)
    {
        return;
    }
    AddFdToFds(fds,c,n);
}    

处理客户端数据

void DealClientData(int fds[],int n,int clifd)
{
    char data[128];
    int num=recv(clifd,data,127,0);
    if (num<=0)
    {
        DelFdFromFds(fds,clifd,n);
        close(clifd);
    }
    else
    {
        printf ("%d:%s\n",clifd,data);
        send(clifd,"ok",2,0);
    }
}

处理select返回的就绪事件

void DealReadyEvent(int fds[],int n,fd_set*fdset,int sockfd)
{
    int i=0;
    for (;i<n;i++)
    {
        if (fds[i]!=-1&&FD_ISSET(fds[i],fdest))
        {
            if(fds[i]==sockfd)
            {
                GetClientLink(sockfd,fds,n);
            }
            else
            {
                DealClientLink(fds,n,fds[i]);
            }
        }
    }
}

主函数

int main()
{
    int sockfd=initsocket();
    assert(sockfd!=-1);
    fd_set readfds;
    int fds[1024];
    initFds(fds,1024);
    AddFdToFds(fds,sockfd,1024);
    while(1)
    {
        int maxfd=SetFdToFdset(&readfds,fds,MAX_FD);
        struct timeval timeout;
        timeout.tv_sec=2;//秒数
        timeout.tv_usec=0;//微秒数
        int n=select(maxfd+1,&readfds,NULL,NULL,&timeout);
        if (n<0)
        {
            printf ("select error\n"); 
            break;   
        }
        else if (n==0)
        {
            printf ("timeout\n");
            continue;
        }
        DealReadyEvent(fds, 1024, &readfds, sockfd);
    }
    exit(0);
}

TCP 的客户端代码如下:
 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
int initsocket()
{
    int sockfd=socket(AF_INET,SOCK_STREAM,0);
    if (sockfd==-1)
        return -1;
    struct sockaddr_in saddr;
    memset(&saddr,0,sizeof (saddr));
    saddr.sin_family=AF_INET;
    saddr.sin_port=htons(6000);
    saddr.sin_addr.s_addr=inet_addr("127.0.0.1");
    int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof (saddr));
    if (res==-1)
        return -1;
    res=listen(sockfd,5);
    if (res==-1)
        return -1;
    return sockfd;
}
int main ()
{
    int sockfd=initsocket();
    assert(sockfd!=-1);
    while(1)
    {
        printf ("please input:");
        char buff[128]={0};
        fgets(buff,127,stdin);
        if (strncmp(buff,"bye",3))
        {
            break;
        }
        int n=send(sockfd,buff,strlen(buff)-1,0);
        if (n<=0)
        {
            printf ("send error\n");
            break;
        }
        memset(buff,0,128);
        n=recv(sockfd,buff,127,0);
        if(n<=0)
        {
            printf ("recv error\n");
            break;
        }
        printf ("%s\n",buff);
    }
    close(sockfd);
    exit(0);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/455954.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

档案库房温湿度管理暂行规定

档案馆温湿度管理暂行规定 来源&#xff1a;本站 日期&#xff1a;2021-8-27 浏览量&#xff1a;1067 档案馆温湿度管理暂行规定 (1985年11月23日国家档案局 国档发〔1985〕42号通知印发) 档案馆是永久保管档案的基地&#xff0c;档案馆建筑是档案馆工作的基础…

用Flutter你得了解的七个问题

Flutter是Google推出的一款用于构建高性能、高保真度移动应用程序、Web和桌面应用程序的开源UI工具包。Flutter使用自己的渲染引擎绘制UI&#xff0c;为用户提供更快的性能和更好的体验。 Flutter使用Dart语言&#xff0c;具有强大的类型、效率和易学能力&#xff0c;基本上你…

前端实战(三):element-ui开关组件的二次封装

目录 二次封装 Switch 开关 原始效果 设计效果 实现步骤 在日常开发过程中&#xff0c;大多数项目主要以 vue 为主&#xff0c;并且现在很多公司仍在使用着 vue。但在使用element-ui组件时通常会遇到一些问题&#xff1a;如组件样式与设计不符合、组件不存在某个功能等等&a…

5年测试经验,自动化都不会?月薪11K都难拿....

我接触了太多测试同行&#xff0c;由于多数同行之前一直做手工测试&#xff0c;现在很迫切希望做自动化测试&#xff0c;其中不乏工作5年以上的同行。 我从事软件自动化测试已经近十年&#xff0c;接触过底层服务端、API 、Web、APP、H5 等等&#xff0c;对自动化算是比较了解…

Spring种存取Bean的5种注解

存取Bean的五种注解 存储Bean对象两种方式1.添加一行bean2.使用注解的方式(5大注解)Controller(控制器存储)Service(服务存储)Repository(仓库存储)Component(组件存储)Configuration(配置存储)方法注解 Bean 获取Bean对象(三种)1.属性注入2.setter注入3.构造方法注入三种注入的…

自动驾驶TPM技术杂谈 ———— CCRT验收标准(测试项目)

文章目录 试验项目行车辅助跟车能力测试方法前车静止识别与响应前车低速识别与响应前车减速识别与响应前车切入识别与响应前车切出识别与响应跟随前车启停 单车道组合控制能力测试方法车道居中保持交通拥堵辅助高速驾驶辅助 换道辅助能力测试方法无干扰车换道有干扰车换道 泊车…

《面试1v1》java泛型

我是 javapub&#xff0c;一名 Markdown 程序员从&#x1f468;‍&#x1f4bb;&#xff0c;八股文种子选手。 面试官&#xff1a;小伙子,说实话,泛型这个机制一开始我也是一头雾水,搞不太明白它到底要解决什么问题。你能不能不那么书呆子,给我普普通通地讲一讲泛型? 候选人…

真正的进步,是创业者和员工的共同进步

再伟大的事业&#xff0c;也是由人一点一滴创造出来的。 人&#xff0c;是企业中最基础的存在&#xff0c;下层基础决定上层建筑&#xff0c;管理公司企业&#xff0c;也是人与人之间的交流问题。 创业十余年&#xff0c;与市场打交道&#xff0c;也与人打交道。 对外&#x…

ArduPilot Kakute F7 AIO DIYF450 之GPS配置

ArduPilot Kakute F7 AIO DIYF450 之GPS配置 1. 源由2. 步骤2.1 模块预测试2.2 物理连接2.3 UART配置2.4 Compass使能2.5 GPS使能2.6 校准Compass 3. GPS & Compass配置效果3.1 Mission Planner界面3.2 QGroundControl界面3.3 ArduPilot配置修改 4. 参考资料 1. 源由 之前…

选址-路径问题(Location-Routing Problem, LRP)

今天为大家介绍的是选址-路径问题(Location-Routing Problem, LRP)&#xff0c;首先上目录 目录 问题简介 基础模型、扩展问题及应用 算法 参考文献 1 问题简介 为了更好地了解这个问题&#xff0c;我们不妨当一波老板。 想象一下我们是经营一家口罩生产企业的老板&am…

RocketMQ基本概念

RocketMQ 一 引言 Message Queue&#xff08;消息 队列&#xff09;&#xff0c;从字⾯上理解&#xff1a;⾸先它是⼀个队列。先进先出的数据结构——队列。消息队列就是所谓的存放消息的队列。 消息队列解决的不是存放消息的队列的⽬的&#xff0c;解决的是通信问题&#x…

C语言实现顺序表--数据结构

魔王的介绍&#xff1a;&#x1f636;‍&#x1f32b;️一名双非本科大一小白。魔王的目标&#xff1a;&#x1f92f;努力赶上周围卷王的脚步。魔王的主页&#xff1a;&#x1f525;&#x1f525;&#x1f525;大魔王.&#x1f525;&#x1f525;&#x1f525; ❤️‍&#x1…

项目管理中引入PMO的应用研究——以H研究所为例

摘 要 本文从项目管理办公室&#xff08;PMO&#xff09;的基本内涵出发&#xff0c;探讨了PMO在以“项目”为主要工作组织方式的H研究所应用过程中发挥的作用、具有的优势、取得的成效与存在的不足&#xff0c;从而实现为企业培养专业的项目经理团队&#xff0c;为业务部门定…

Ubuntu20.04安装CUDA和CUDNN

CUDA是GPU深度学习的运行库&#xff0c;那么cuDNN就是训练加速工具&#xff0c;两者要相互配合使用&#xff0c;所以一般机器学习需要训练引擎(tensorflow-gpu) CUDA cuDNN使用。想不安装cuDNN是不可以的&#xff0c;而且cuDNN版本要和CUDA版本相互搭配。 1、前置工作 查看…

最新动态 | 大势智慧参加广东省应急测绘保障与安全生产演练

4月20日&#xff0c;2023年度广东省应急测绘保障与安全生产演练在台山市赤溪镇鱼塘湾举行。本次演练由广东自然资源厅主办&#xff0c;广东省国土资源测绘院、江门市自然资源局和台山市人民政府承办。在省市各指导单位与参演单位的多方协同与指挥下&#xff0c;应急测绘保障与安…

常用PLC学习资料下载地址

常见PLC的资料一般在官网都可以找到&#xff0c;今天整理一下&#xff0c;把西门子、三菱、欧姆龙、汇川四家品牌的官方下载地址直接贴出来供大家直接使用。 1、汇川技术官方网站 汇川技术 - 推进工业文明 共创美好生活 (inovance.com)https://www.inovance.com/2、汇川技术资料…

TCP重传、滑动窗口、流量控制、拥塞控制

目录 重传机制 #超时重传 SACK 方法 Duplicate SACK 滑动窗口 流量控制 窗口关闭 拥塞控制 慢启动 拥塞避免算法 拥塞发生 快速恢复 重传机制 TCP 实现可靠传输的方式之一&#xff0c;是通过序列号与确认应答。 在 TCP 中&#xff0c;当发送端的数据到达接收主机时…

rancher部署flink集群

rancher版本&#xff1a;v2.6.8 k8s版本&#xff1a;v1.22.13rke2r1 flink集群版本&#xff1a;1.15.0 flink安装模式&#xff1a;session cluster 写在前面&#xff1a;因为参照官网的说明安装过程中出现了很多问题&#xff0c;特记录于此&#xff0c;避免后续重复踩坑 目…

FE_CSS 精灵图技术 字体图标 CSS三角

一个网页中往往会应用很多小的背景图像作为修饰&#xff0c;当网页中的图像过多时&#xff0c;服务器就会频繁地接收和发送请求图片&#xff0c;造成服务器请求压力过大&#xff0c;这将大大降低页面的加载速度。 因此&#xff0c;为了有效地减少服务器接收和发送请求的次数&a…

国内申请日本专利有哪些流程?

日本2004年修订的实用新型法已经于2005年4月1日生效&#xff0c;在日本&#xff0c;“专利”这一概念限于发明&#xff0c;实用新型和外观设计均不称为专利。实用新型授权后&#xff0c;就叫实用新型权&#xff0c;并不叫专利权。而且&#xff0c;发明、实用新型和外观设计是“…