【Linux网络编程】select多路复用

举报
人才程序员 发表于 2023/07/26 11:35:59 2023/07/26
【摘要】 @TOC 前言我们上节课讲解了服务端的编程(Linux服务端编程初体验)本节课要讲的是select提示:以下是本篇文章正文内容,下面案例可供参考 如何增强服务端的通信能力如何增强服务端的能力,同时支持很多个客户端?1、有同学说:用多线程啊!这个回答可以完成,但有缺陷:太占用系统的资源了所以:我们的select就诞生了 Linux的设计哲学一切都是文件!Linux中文件是什么1、文件系统中物理...

@TOC


前言

我们上节课讲解了服务端的编程(Linux服务端编程初体验)
本节课要讲的是select


提示:以下是本篇文章正文内容,下面案例可供参考

如何增强服务端的通信能力

如何增强服务端的能力,同时支持很多个客户端?
1、有同学说:用多线程啊!
这个回答可以完成,但有缺陷:太占用系统的资源了

所以:我们的select就诞生了

Linux的设计哲学

一切都是文件!

Linux中文件是什么
1、文件系统中物理意义上的文件
2、Linux管理的一切对象

文件描述符

他就是一个非负整数值,一个句柄
如果学习过Windows的小伙伴应该知道什么是句柄
没有学过也不要紧,他就是一个非负整数值

作用:
1、与内核交互
2、内核通过他操作对应的数据结构

玩法:

1、open
2、read
3、write
4、close

Linux文件编程模式:

int fd = open("Dev",O_RDWR);
if(fd!=-1)
{
	char buf[32] = {0};
	int len = read(fd,buf,sizeof(buf));
	
	len = write(fd,buf,len);
	
	close(fd);
}

代码讲解

注意:在Linux中,我们不需要open打开文件close关闭文件,因为内核已经帮忙打开了

函数原型讲解

write(fd,void *p,size_t s);//参数1:要操作的文件描述符,参数2:要写入的地址,写入的大小
int read(fd,void *p,size_t readsize);//参数1:要操作的文件描述符,参数2:存储的地址,读出的大小
#include <stdio.h>
#include <unistd.h>

int main()
{
    int iofd = 0;
    char s[] = "csdn\n";
    int len = 0;

    write(0, s, sizeof(s));

    len = read(0, s, 5);
    
    s[len] = 0;

    printf("%s\n", s);

    return 0;
}

结果:
在这里插入图片描述
所以我们可以说:write和printf的功能是一样的
read和scanf的功能是一样的

以文件方式操作命令行

阻塞函数与非阻塞函数

阻塞函数:
要等某个事件发生了才返回

非阻塞函数:
函数调用后可以及时返回(仅仅标记等待的事件)
事件发生后以回调的方式传递

轮询

轮询指依次询问每个相关设备是否需要服务的方式
轮询可以解决阻塞函数导致程序无法进行的问题

select()

功能:用于监视指定的文件描述符是否产生事件

int select(int maxfd,
				fd_set*readset,
				fd_set*writeset,
				fd_set*excepset,
				const struct timeval*timeout);

参数1:指定的文件描述符
参数2:从readset里看有没有读事件发生,有:标记
参数3:从writeset里看有没有写事件发生
参数4:从excepset里面看有没有哪个有错误
参数5:多久没有响应为超时

返回值:
当返回值>0:有事件
当返回值==0:无事件

select()多路复用的使用步骤:

1、设置文件描述符
2、设置监听范围
3、设置监听超时
4、调用select
5、查看监听结果
6、处理目标事件
7、调用select....

fd_set的意义
就是一个装着文件描述符的数组

操作函数

FD_ZERO(fd_set *fdset);//将fdset里面的所有位设置成0
FD_SET(int fd,fd_set *fd fdset);//设置fd到fdset中
FD_CLR(int fd,fd_set *fdset);//从fdset中删除fd
FD_ISSET(int fd,fd_set *fdset);//判断fd在不在fdset中

代码全貌

#include <sys/select.h>
#include <sys/time.h>
#include <stdio.h>
#include <unistd.h>

int main()
{
    int len = 0;
    fd_set reads = {0};
    fd_set temps = {0};
    struct timeval timeout = {0};
    int iofd = 0;
    char s[32] = {'\0'};

    FD_ZERO(&reads);
    FD_SET(iofd, &reads);

    while( 1 )
    {
        int r = -1;

        temps = reads;

        timeout.tv_sec = 0;
        timeout.tv_usec = 50000;

        r = select(1, &temps, 0, 0, &timeout);

        if( r > 0 )
        {
            len = read(iofd, s, sizeof(s)-1);

            s[len] = 0;

            printf("Input: %s\n", s);
        }
        else if( r == 0 )
        {
            static int count = 0;

            usleep(10000);   // do something else

            count++;

            if( count > 100 )
            {
                printf("do something else\n");

                count = 0;
            }
        }
        else
        {
            break;
        }
    }

    return 0;
}

需要注意的细节:
其中iofd为文件操作符
reads用于保存文件操作符
temps用于select()函数
原因:select()函数调用后,temps里面就只剩有信号的fd了,因为reads不能丢,所以不能直接设置reads到里面,因为temps里面就只剩有信号的fd了,所以每次reads里面的也要赋值到temps里
maxfd = iofd+1;

temeval成员:

timeout.tv_sec = 0;//延时多少秒
timeout.tv_usec = 50000;//延时多少毫秒

The End

做这博客也是很难的,望大家的点赞关注!

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。