前言
我们上节课讲解了服务端的编程(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
做这博客也是很难的,望大家的点赞关注!