文章目录
- 前言
- 如何增强服务端的通信能力
- Linux的设计哲学
- 文件描述符
- 代码讲解
- 以文件方式操作命令行
- 阻塞函数与非阻塞函数
- 轮询
- select()
- 代码全貌
- The End
前言
我们上节课讲解了服务端的编程(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
做这博客也是很难的,望大家的点赞关注!