基于select系统调用的Linux Socket通信【服务端】
选择(select)服务器是一种比较常见的服务器模型。利用select系统调用可以使Linux socket应用程序同时管理多个套接字。使用select可以当执行操作的套接字满足可读或者可写条件时,给应用程序发送通知。收到这个通知后,应用程序再去调用相应的收发函数进行数据的接收或发送。
当用户进程调用了select,那么整个进程会被阻塞。与此同时,内核会“监视”所有select负责的socket,当人格一个socket中的数据准备好时,select就会返回。这时用户进程再调用read操作,将数据从内核拷贝到用户进程。
select()函数
int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
函数参数:
- nfds:输入参数,告诉内核要监控文件描述符的范围,一般取值为最大文件描述符+1
- readfds:既是输入参数也是输出参数。输入参数:告诉内核要监控哪些文件描述符;输出参数:内核告诉应用程序哪些文件描述符有变化
- writefds:既是输入参数也是输出参数。输入参数:告诉内核要监控哪些文件描述符;输出参数:内核告诉应用程序哪些文件描述符有变化
- exceptfds:既是输入参数也是输出参数。一般表示异常事件
- timeout:超时时间。NULL:表示永久阻塞,直到有事件发生;0:表示不阻塞,不管有没有事件发生,都会立刻返回;>0:表示阻塞的时长,若没有超过时长,则一直阻塞,若在时长内,有事件发生,则立刻返回,若超过时长,则立刻返回。返回值:成功返回发生变化的文件描述符个数
使用select开发服务端流程:
- 创建socket,得到监听文件描述符–socket();
- 设置端口复用–setsockopt();
- 将ldf与IP PORT绑定–bind();
- 设置监听–listen();
- 具体通信步骤(伪代码)
fd_set readfds; //定义文件描述符集变量
fd_set tmpfds;
FD_ZERO(&readfds); //清空文件描述符集变量
FD_SET(lfd,&readfds); //将ldf加入到readfds集合中;
maxfd=lfd;
while(1){
tmpfds=readfds;
nready = select(maxfd+1, &tmpfds, NULL,NULL,NULL);
if(nready<0){
if(errno==EINTR){
//被信号中断
continue;
}
break;
}
//有客户端连接请求到来
if(FD_ISSET(lfd,&tmpfds)){
//接受新的客户端连接请求
cfd=accept(lfd,NULL,NULL);
//将cfd加入到readfds集合中
FD_SET(cfd,&readfds);
//修改内核监控的文件描述符的范围
if(maxfd<cfd){
maxfd=cfd;
}
if(--nready==0){