101-Linux_I/O复用方法之select

news2024/11/25 16:38:44

文章目录

  • 1.select系统调用的作用
  • 2.select系统调用的原型
  • 3.集合fdset
  • 4.使用select实现TCP服务器
    • (1)服务器端代码:
    • (2)客户端代码
    • (3)运行结果截图

1.select系统调用的作用

在一段指定时间内,监听用户感兴趣的文件描述符的可读、可写和异常等事件

2.select系统调用的原型

#include <sys/select.h>
int select(int maxfd, fd_set readfds, fd_setwritefds, 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 结构如下:

#define __FD_SETSIZE 1024
typedef long int __fd_mask;
#define __NFDBITS (8 * (int) sizeof (__fd_mask))
typedef struct
 {
 #ifdef __USE_XOPEN
 __fd_mask fds_bits[__FD_SETSIZE / __NFDBITS];
# define __FDS_BITS(set) ((set)->fds_bits)
#else
__fd_mask __fds_bits[__FD_SETSIZE / __NFDBITS];
 # define __FDS_BITS(set) ((set)->__fds_bits)
 #endif
} fd_set;
通过下列宏可以访问 fd_set 结构中的位:
 FD_ZERO(fd_set *fdset); // 清除 fdset 的所有位
FD_SET(int fd, fd_set *fdset); // 设置 fdset 的位 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 将一直阻塞,直到某个文件描述符就绪

3.集合fdset

在这里插入图片描述

4.使用select实现TCP服务器

(1)服务器端代码:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>
#include<string.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<sys/select.h>
#include<sys/socket.h>

#define MAXFD 10
int socket_init();
int accept_client(int sockfd);
void fds_init(int fds[])
{
    for(int i=0;i<MAXFD;i++)
    {
        fds[i]=-1;
    }
}

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

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

int main()
{
    int fds[MAXFD];//记录描述符
    fds_init(fds);
        
    int sockfd=socket_init();//监听套接字
    if(sockfd==-1)
    {
        exit(0);
    }

    fds_add(sockfd,fds);

    fd_set fdset;//集合收集描述符

    while(1)
    {
        FD_ZERO(&fdset);
        int maxfd=-1;

        for(int i=0;i<MAXFD;i++)
        {
            if(fds[i]==-1)
            {
                continue;
            }
            FD_SET(fds[i],&fdset);//将数组中有效的描述符添加到集合
            if(fds[i]>maxfd)
            {
                maxfd=fds[i];
            }
        }
        struct timeval tv={5,0};

        int n=select(maxfd+1,&fdset,NULL,NULL,&tv);//阻塞
        if(n==-1)
        {
            printf("select error\n");
        }
        else if(n==0)
        {
            printf("time out\n");
        }
        else
        {
            for(int i=0;i<MAXFD;i++)
            {
                if(fds[i]==-1)
                {
                    continue;
                }
                if(FD_ISSET(fds[i],&fdset))
                {
                    if(fds[i]==sockfd)//监听套接字,用accept处理
                    {
                        int c=accept_client(sockfd);
                        if(c!=-1)
                        {
                            fds_add(c,fds);//添加新接收的连接
                        }
                    }
                    else//recv
                    {
                        char buff[128]={0};
                        int num=recv(fds[i],buff,127,0);
                        if(num<=0)
                        {
                            close(fds[i]);
                            fds_del(fds[i],fds);
                        }
                        else

                        {
                            printf("recv:%s\n",buff);
                            send(fds[i],"ok",2,0);
                        }
                    }

                }

            }
        }

    }
}
int socket_init()
{
    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(5678);
    saddr.sin_addr.s_addr=inet_addr("127.0.0.1");
    int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
    if(res==-1)
    {
        printf("bind error\n");
        return -1;
    }

    res=listen(sockfd,5);
    if(res==-1)
    {
        return -1;
    }

    return sockfd;
}
int accept_client(int sockfd)
{
    struct sockaddr_in caddr;
    int len=sizeof(caddr);
    int c=accept(sockfd,(struct sockaddr*)&caddr,&len);
    return c;
}

(2)客户端代码

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>

int socket_init();

int main()
{
    int sockfd=socket_init();
    if(sockfd==-1)
    {
        exit(0);
    }

    while(1)
    {
        printf("input:");
        char buff[128]={0}; 
        fgets(buff,127,stdin);
        if(strncmp(buff,"end",3)==0)
        {
            break;
        }
        send(sockfd,buff,strlen(buff)-1,0);

        memset(buff,0,128);
        recv(sockfd,buff,127,0);
        printf("read:%s\n",buff);
    }
    close(sockfd);
    exit(0);
        
}

int socket_init()
{
    int sockfd=socket(AF_INET,SOCK_STREAM,0);//tcp流式服务
    if(sockfd==-1)
    {
        printf("socket errror\n");
        return -1;
    }

    struct sockaddr_in saddr;
    memset(&saddr,0,sizeof(saddr));    saddr.sin_family=AF_INET;
    saddr.sin_port=htons(5678);
    saddr.sin_addr.s_addr=inet_addr("127.0.0.1");


    int res=connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
    if(res==-1)
    {
        printf("connect error\n");
        return -1;
    }

    return sockfd;
}

(3)运行结果截图

在这里插入图片描述

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

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

相关文章

Typora Markdown 中 LaTeX 公式居左、对齐的方法

我们知道公式块里的公式默认是居中的&#xff0c;我们想让公式居左&#xff08;顶着左页面&#xff09;可以使用如下格式的 flalign 数学环境&#xff1a; 不多说&#xff0c;先看示例 示例 \begin{flalign} &\iint_D\frac{\sin y}{y}{\rm d}\sigma\\ &\int_0^1{\rm…

【redis】redis分布式锁(二)可重入锁+设计模式

【redis】redis分布式锁&#xff08;二&#xff09;可重入锁 文章目录 【redis】redis分布式锁&#xff08;二&#xff09;可重入锁前言一、可重入锁&#xff08;又名递归锁&#xff09;1、说明&#xff1a;2、分开解释&#xff1a;3、可重入锁的种类隐式锁&#xff08;即synch…

Nautilus Chain 测试网第二阶段,推出忠诚度计划及广泛空投

随着更多的公链底层面向市场&#xff0c;通过参与早期测试在主网上线后获得激励成为了行业的一个热点话题&#xff0c;在Apots、Arbitrum One、Optimism等陆续发放了测试空投后&#xff0c;以Layer3为主要特性的Nautilus Chain也在前不久明确表示将会有空投&#xff0c;引发行业…

《嵌入式系统》知识总结3:STM32微控制器

STM32系列产品命名规则 以stm32f103zet6为例 Stm32微控制器架构 模块 • 处理器核心 • 存储器 • 时钟电路、系统总线 • 外设&#xff08;硬件单元&#xff09;&#xff1a;I/O接口、通信接口、定时器 、ADC和DAC&#xff0c; …… 系统结构 哈佛存储结构 • 独立的…

mockjs学习笔记

文章目录 一、什么是mockjs二、安装mockj项目安装mock 三、mock语法生成字符串生成文本生成标题和句子生成段落生成数字生成自增id生成姓名-地址-身份证随机生成图片生成时间 mock拦截请求定义get请求定义post请求 四、实现新闻管理案例获取数据添加新闻删除新闻 一、什么是moc…

有趣的地理题

题目 总部位于上海的“哔哩哔哩”&#xff08;简称B站&#xff09;&#xff0c;是国内知名的视频网站。在B站投稿的用户被称为“UP主”。据统计&#xff0c;B站的UP主群体中&#xff0c;来自上海的比例最高&#xff0c;200万粉丝以上的UP主&#xff0c;来自上海的比例超过 30 …

最佳Midjourney动漫相关风格提示词,值得收藏

先补充概念&#xff0c;后面慢慢补图片咯 动漫艺术家 下面是一些最伟大的艺术家的名单 Hayao Miyazaki, Co-founder of Studio Ghibli&#xff08;宫崎骏&#xff0c;吉卜力工作室的共同创始人&#xff09;Eiichiro Oda, One Piece&#xff08;织田荣一郎&#xff0c;《海贼…

【Linux】Linux下常见基本指令

&#x1f331;博客主页&#xff1a;大寄一场. &#x1f331;系列专栏&#xff1a;Linux &#x1f618;博客制作不易欢迎各位&#x1f44d;点赞⭐收藏➕关注 目录 前言 一、文件和目录操作指令 ls指令 pwd指令 cd指令 touch指令 rmdir指令 && rm 指令&#xff1a; man指…

吉布斯采样方法

吉布斯采样方法 对于多元分布, P ( X ) , X [ x 1 x 2 ] P(X), X\left[\begin{array}{l} x_1 \\ x_2 \end{array}\right] P(X),X[x1​x2​​]吉布斯抽样执行如下。假设很难从联合分布中抽样 P ( x 1 , x 2 ) P\left(x_1, x_2\right) P(x1​,x2​)但是从条件分布 P ( x 1 ∣ …

一键轻松拥有自己专属的 ChatGPT 网页版,搭建一个私人的可随时随地访问的ChatGPT网站

前言 ChatGPT是一种基于Transformer架构的自然语言处理模型&#xff0c;由OpenAI开发。GPT是“Generative Pre-trained Transformer”的缩写&#xff0c;意为“预训练生成式Transformer模型”。 ChatGPT模型是一种无监督学习模型&#xff0c;它可以在大规模文本数据上进行预训…

scratch比大小 中国电子学会图形化编程 少儿编程 scratch编程等级考试三级真题和答案解析2023年3月

目录 scratch比大小 一、题目要求 1、准备工作 2、功能实现 二、案例分析

【react从入门到精通】深入理解React生命周期

文章目录 前言React技能树React的生命周期是什么React v16.0前的生命周期组件初始化(initialization)阶段组件挂载(Mounting)阶段组件更新(update)阶段组件销毁阶段 React v16.4 的生命周期总结写在最后 前言 在上一篇文章《react入门这一篇就够了》中我们已经掌握了React的基本…

软件STM32cubeIDE下STM32F1xx和STM32F4xx使用:备份寄存器+复位标志位-基础样例

软件STM32cubeIDE下STM32F1xx和STM32F4xx使用&#xff1a;备份寄存器复位标志位-基础样例 1、前言2 、 实验环境3、自我总结&#xff08;1&#xff09;对于备份寄存器&#xff08;BKP&#xff09;:&#xff08;2&#xff09;对于复位标志位&#xff08;RCC_CSR&#xff09;&…

【5G RRC】RSRP、RSRQ以及SINR含义、计算过程详细介绍

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…

一道经典的小学数学题,和它背后的贪心算法(35)

小朋友们好&#xff0c;大朋友们好&#xff01; 我是猫妹&#xff0c;一名爱上Python编程的小学生。 欢迎和猫妹一起&#xff0c;趣味学Python。 今日主题 这个五一小长假&#xff0c;你玩得怎么样&#xff1f; 今天&#xff0c;咱们先做一道经典的小学数学题&#xff0c;…

Enabling Fast and Universal Audio Adversarial Attack Using Generative Model

Enabling Fast and Universal Audio Adversarial Attack Using Generative Model https://www.winlab.rutgers.edu/~yychen/ AAAI 2021 文章目录 Enabling Fast and Universal Audio Adversarial Attack Using Generative ModelAbstractIntroductionLimitations of Prior WorkT…

每日一个小技巧:1招教你怎么将照片无损放大

照片是一种记录、分享和保存记忆的重要方式。它可以记录特殊的时刻和经历&#xff0c;如毕业典礼、婚礼、旅游等&#xff0c;为我们锁住美好回忆。不知道大家有没有经历过&#xff0c;在手机或者电脑上打开一张拍摄的照片&#xff0c;却发现它的尺寸太小了&#xff0c;手动放大…

C语言从入门到精通

文章目录 C语言1.helloworld1.1 pause1.2 cls清屏1.3 加法运算1.4 hello 2 常量变量和数据类型2.1 常量2.2 变量2.3 sizeof数据类型大小2.4 无符号整型2.5 字符类型2.5.1 字符类型简介2.5.2 字符类型运算 2.6 实数型2.7 进制和转换2.8 数据溢出 3. 运算符和分支循环语句3.1 字符…

D. Decorate Apple Tree(记录每个点,叶子节点数目)

Problem - D - Codeforces 在Arkady的花园里有一棵苹果树。它可以表示为连接着枝干的节点集合&#xff0c;以便从任何一个节点到达任何其他节点时只有一种方法。节点从1到n进行编号&#xff0c;节点1称为根。 节点v的子树是指一组节点u&#xff0c;使得从u到根的路径必须经过v…

基于SpringBoot+Vue+Java的社区医院管理服务系统(附源码+数据库)

摘 要 在Internet高速发展的今天&#xff0c;我们生活的各个领域都涉及到计算机的应用&#xff0c;其中包括社区医院管理服务系统的网络应用&#xff0c;在外国线上管理系统已经是很普遍的方式&#xff0c;不过国内的管理系统可能还处于起步阶段。社区医院管理服务系统具有社区…