select函数详解及其在I|O复用模型中的应用
来源:互联网 发布:bae 数据库 编辑:程序博客网 时间:2024/06/04 05:43
一.select函数详解
#include <sys/select.h>
#include <sys/time.h>
int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *excptset, const strcut timeval *timeout)
返回:准有就绪的文件描述数量,若超时则返回0,否者返回-1
针对select中最后一个时间参数情况如下
struct timeval{ long tv_sec;//seconds long tv_usec;//microseconds};
1.timeout = NULL
表示将会一直等待下去,并且堵塞。也有可能系统捕获到了异常信号,强制返回-1.
2.time->tv_sec != 0 && timeout->tv_usec != 0
timeout作为计时器,进行倒计时,如果超时了那么,select函数就会返回0。也有可能系统捕获到了异常信号,强制返回-1.
3.time->tv_sec == 0 && timeout->tv_usec == 0
将会以轮训的方式等待下,还没有准备就绪的描述符。
针对select返回值详细分析
1.负值
系统捕捉到信号,进入相应的信号处理函数。
2.0
等待超时
3.正值
表示有多少个描述符号准备就绪
fd_set的宏操作函数
FD_ZERO(fd_set *fdset) //clear all bit in fdset
FD_SET(int fd, fd_set *fdset) //turn on the bit for fd on fdset
FD_ISSET(int fd, fd_set *fdset) // is on the bit for fd on fdset ?
FD_CLR(int fd, fd_set *fd_set) //turn offthe bit for fd on fdset
在sys/select函数中规定,FD_SETSIZE的值表示描述符总数,一般值默认为1024。但是在不同64位中的值可能不同。
二.select函数的应用
针对客服端一方,我们设计了一个select在批量输入中的一个模型。但是该明显存在一个大量的陷阱,如下分析所示
#include "unp"void doClient_echo(FILE *fp, int sockfd){ fd_set rset; int maxfdp; FD_ZERO(&rset); char recvbuf[MAXLINE], sendbuf[MAXLINE]; for(;;){ FD_SET(fileno(fp), &rset); FD_SET(sockfd, &rset); maxfdp = fileno(fp)+1; Select(maxfdp, &rset, NULL, NULL, NULL); if(FD_ISSET(fileno(fp), &rset)){ if(Fgets(fp, sendbuf, MAXLINE) != EOF) return; Write(sockfd, sendbuf, strlen(sendbuf)); } if(FD_ISSET(sockfd, &rset)){ int n; if((n = Readline(sockfd, recvbuf, MAXLINE)) == 0) std::cout << "do_client: server terminaled\n"; Fputs(recvbuf, stdout); } }}
在cilent的发送速度和server相同的情况下,当在client通过循环发送8个请求给server后,当打算发送第九个请求的时候Fgets函数读取到了EOF,
这个时候返回空指针,这个时候函数返回。但是client的接受端并没有完全接受到来之server处理完的信息函数就返回了,这样就会造成数据的丢失。
因为虽然我们完成了从套接字的读入,但是请求可能还在前往去服务器的路上,或者是请求对应的处理消息还在从服务器到客服端的路上。
针对上诉的描述问题我们给出了如下的解决方案。
#include "unp"#define MAXLINE 4096void doClient_echo(FILE *fp, int sockfd){ int maxfdp; fd_set rset; FD_ZERO(&rset); int stdineof = 0; char sendbuf[MAXLINE],recvbuf[MAXLINE]; for(;;){ if(stdineof == 0) FD_SET(fileno(fp), &rset); FD_SET(sockfd, &rset); maxfdp = fileno(fp) + 1; Select(maxfdp, &rset, NULL, NULL, NULL); if(FD_ISSET(sockfd, &rset)){ int n; if((n = Readline(sockfd, recvbuf, MAXLINE)) == 0){ if(stdineof == 1) return; else{ std::cout << "Server terminated prematurely\n"; } } Write(STDOUT_FILENO, recvbuf, n); } if(stdineof == 0 && FD_ISSET(fileno(fp), &rset)){ int n; if((n = Readline(fileno(fp), sendbuf, MAXLINE)) == EOF){ stdineof = 1; Shutdown(sockfd, SHUT_WR); FD_CLR(fileno(fp), &rset); continue; } Write(sockfd, sendbuf, n); } }}
根据要求只有当请求发送完毕后,然后client接收了处理的全部要求,然后才能返回函数。但是根据TCP|IP四次握手的原则,所有的请求发送完毕后,通过调用shutdown函数半关闭套接字写入端口,最后一个信息就是有cilent发送一个FIN单字节,促使server被动关闭套接字,进入tcp|ip四次挥手过程。(该过程不在详述,请参考待定)
1.stdineof = 0,表示fp文件指针还可以继续读取,请求。当fp文件读取完成后,Readline函数返回EOF表示请求读取完毕,这个时候通过调用shutdown函数半关闭套接字写入端口,然后将该文件fp对应的文件描述符号,从rset描述符集合中除去。
2.目前等待一直从套接字描述符号中读取对应的请求的处理,并且答应出来,当读写出来的数据为“处理n”的时候表示是对“请求n”的处理结果,在sockfd读取结果为0的时候,表示收到的连接为ACK,如果stdineof = 1,那么该ACK很有可能就是由自己发送的FIN结束请求的应答,以此来表示结束函数。
- select函数详解及其在I|O复用模型中的应用
- 【整理】I/O复用模型中的 select、poll、epoll
- Linux I/O复用之select函数详解
- Linux I/O复用之select函数详解
- I/O复用模型之select
- I/O复用之select模型
- select函数详解及其应用
- I/O复用模型之select函数用法——服务器开发
- Unix Socket编程--I/O复用之select模型
- Unix Socket编程--I/O复用之select模型
- Unix Socket编程--I/O复用之select模型
- I/O复用模型之select学习
- Linux网络编程---I/O复用模型之select
- 网络编程之I/O复用模型select
- I/O多路复用技术详解之select模型
- select I/O模型用法
- I/O多路复用 select模型
- I/O模型以及select和poll函数
- FreeImage 3.17.0 在VS2015下编译及遇到问题解决
- pcie 驱动程序分析
- JAVA选择排序
- js日历控件
- struts2粗略总结
- select函数详解及其在I|O复用模型中的应用
- 1048. 数字加密(20)
- 计算机进制转换
- 基于vue-cli及express模拟Ajax获取服务器数据
- Spring学习之Bean的装配
- JAVA冒泡排序,归并排序,二分查找
- Vue和VueResource介绍
- codeforces 590D
- 3分钟把区块链的技术与应用彻底讲清楚