网络编程第6章:select和poll

select

#include<sys/select.h>
#include<sys/time.h>
int select(int maxfdql,fd_set *readset,fd_set *wirteset,fd_set*exceptset,const struct timvale *timeout){}
int select(待测试的描述符个数(值是待测试的最大描述符加1),测试读写异常条件的描述符,任何一个就绪所花费的时间),

改函数返回的时候,三个描述符集合,结果将显示哪些描述符已经就绪,(未就绪描述符值将为0),所以每次调用select的时候,都要待测试描述符置位1.1

关于timeout这是一个结构体变量,如下

struct timeval {
	long tv_sec;//秒
	long tv_uscc;//微妙
}//表示内核等待一个描述符就绪需要花费多少时间

这个参数有三种可能:
设置为空值:仅在有一个描述符就绪的时候才返回,否则永远等待下去
等待一段固定的时间:在指定时间内如果有就绪就返回
不等待:设置为0的时候,轮询进行检查

描述符的测试:

描述符集是fd_set,首先进行初始化,

fd_set rset;
FD_ZERO(rset);
FD_SET(1,set);
FD_SET(3,set);

三个描述符集是值–结果参数,在函数返回的时候,任何未就绪描述符将会置位0.所以每次调用select的时候,都要待测试的描述符置为1.
这个函数的返回值是就绪描述符的个数.

就绪条件

-接收低水位标记是让select返回“可读”时套接字接收缓冲区中所需的数据量。对于TCP和UDP,其默认值为1-发送低水位标记是让select返回“可写”时套接字发送缓冲区中所需的可用空间。对于TCP,其默认值为2048。
对于UDP,只要一个UDP套接字的发送缓冲区大小大于该套接字的低水位标记,该UDP套接字就总是可写。

描述符准备好读的就绪条件:
1 如果接收缓冲区的数量大于套接字低水位标记的当前大小(我理解的是内容可以被读入套接字缓冲区的时候) ,
2 接收了FIN
3 监听套接字完成的连接数不为0
4 有错误待处理

描述符准备好写的就绪条件:
1 套接字缓冲区数量大于发送缓冲区的低水位标记
2 写半部关闭?
3 connect执行完毕(已经建立链接或者链接已经以失败告终)
4 有套接字错误待处理

阻塞于select的客户端处理程序

#include "unp.h"
void str_cli(FILE *fp,int sockfd){
	int maxfdp1;
	fd_set rset;
	char sendline[MAXLINE],recvline[MAXLINE];
	FD_ZERO(&rset);
	for(;;){
		FD_SET(fileno(fd),&rset);
		FD_SET(sockfd,&rset);
		maxfdp1=max(fileno(fd),sockfd)+1;
		select(maxfdp1,&rset,NULL,NULL,NULL);
		if(FD_ISSET(sockfd,&rset)){//如果套接字可读
			if(Readline(scokfd,recvline,MAXLINE)==0){
					printf("服务器意外终止");
			}
			Fputs(revline,stdout);
		}
		if(FD_ISSET(fileno(fd),&rset)){//如果标准输入可读
			if(Fgets(sendline,&rset)==NULL){
				return  ;
			}
			writen(sockfd,sendline,strlen(sendline));	
		}
	}
}

但是这个并不正确:
原因:输入EOF之后,这个函数返回到main函数,然后客户端程序终止,但是仍旧有报文存在于网络中,在传输中的报文来不及接收客户端就终止了.
这个错误可以使用shutdown函数来关闭TCP一半连接.

shutdown 函数:

shutdown函数可以关闭读链接,写链接,连接.
shutdown函数是无关于close的引用计数的

int shutdown(int sockfd,int howto);

howto:
SHUT_RD:关闭读
SHUT_WR:关闭写
SHUT_RDWR:关闭连接

poll函数:

#include<poll.h>
int poll(struct pollfd *fdarray,unsigned long nfds,int timeout)
其中:
struct{
	int fd;
	short events;//测试的条件
	short revents;//返回该描述符的状态
}
int poll(测试数组(值结果参数),第一个数组的个数,等待时间)
返回值,如果为负数,那么就是发生错误,否则返回就绪的描述符个数
如果不再关心某个描述符,就把其对应的fd设置为0

关于引起poll返回的条件:P145

#include "unp.h"
#include<sys/socket.h>
int main(int argc,char **argv){
	int i,max,listenfd,connfd,sockfd;
	int nready;
	ssize_t n;
	char buf[MAXLINE];
	socklen_t clilen;
	struct pollfd client[OPEN_MAX];
	struct sockaddr_in cliaddr,servaddr;
	listenfd = socket(AF_INET,SOCK_STREAM,0);
	bzero(&servaddr,sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servaddr.sin_port = htons(SERV_PORT);
	bind(listenfd,(SA*)&servaddr,sizeof(servaddr));
	
	listen(listenfd,LISTENQ);
	client[0].fd = listenfd;
	client[0].evets = POLLRDNORM;
	for(int i=1;i<OPEN_MAX;i++)
		client[i].fd = -1;//将其他置位不可用的时间
	maxi=0;
}

for(;;){
	nready =Poll(client,maxi+1,INFTIM);
	if(client[0].revents && POLLRDNORM){//如果有了新链接
		client = sizeof(cliaddr);
		connfd = accept(listenfd,(SA*)&cliaddr,&clilen);//接收一个新的套接字
		for(int i=1;i<OPEN_MAX;i++){
			if(client[i].fd<0){
				client[i].fd = connfd;
				break;
			}
		}
		if(i==OPENMAX){
			printf("太多客户端");
		}
		if(--nready<=0){//没有更多客户
			continue;
		}	
	}
	for(int i=1;i<=maxi;i++){
		if((sockfd=client[i].fd)<0)continue;
		if(client[i].revents & (POLLRDNORM | POLLERR)){
			if((n=read(sockfd,buf,MAXLINE))<0){
				if(errno == ECONNRESET){
					close(sockfd);
					client[i].fd=-1;
				}else{
					err_sys("读入错误");
				}
			}else if(n==0){
				close(sockfd);
				client[i].fd=-1
			}else  writen(sockfd,buf,n);
			
			if(--nready<=0)break;
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值