[第三版]单线程多路复用
第二版的问题
第二版中存在一个问题, 当服务端进程意外终止, 如果客户端正阻塞在输入时, 那么无法接收到通知, 直到按下回车发送时报错才得知服务端已经关闭
client
#include "unp.h"
void str_cli(FILE *fp,int sockfd);
int main(int argc,char *argv[]){
int sockfd,i;
struct sockaddr_in servaddr;
if(argc != 2)
err_quit("usage: client <ip address>");
sockfd=Socket(AF_INET,SOCK_STREAM,0);
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family=AF_INET;
servaddr.sin_port=htons(13);
inet_pton(AF_INET,argv[1],&servaddr.sin_addr);
Connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
str_cli(stdin,sockfd);
exit(0);
}
void str_cli(FILE *fp,int sockfd){
char buff[MAXLINE];
fd_set rset;
int maxfdp1,stdineof;
int n;
stdineof=0;
FD_ZERO(&rset);
for(;;){
if(stdineof == 0)
FD_SET(fileno(fp),&rset);
FD_SET(sockfd,&rset);
maxfdp1=max(fileno(fp),sockfd)+1;
Select(maxfdp1,&rset,NULL,NULL,NULL);
if(FD_ISSET(sockfd,&rset)){
if((n=Read(sockfd,buff,MAXLINE)) == 0){
if(stdineof == 1)
return;
else
err_quit("str_cli: server terminated prematurely");
}
Write(fileno(stdout),buff,n);
}
if(FD_ISSET(fileno(fp),&rset)){
if((n=Read(fileno(fp),buff,MAXLINE)) == 0){
stdineof = 1;
shutdown(sockfd,SHUT_WR);
FD_CLR(fileno(fp),&rset);
continue;
}
writen(sockfd,buff,n);
}
}
}
serv
几点说明:
变量i,sockfd功能相近, 遍历时用
client[FD_SETSIZE]用来保存所有需要读取的fd
maxfd与client中最大的fd相同, maxi是这个最大fd在client中的下标
nready保存当前已经准备就绪的fd数量
#include "unp.h"
int main(int argc, char *argv[]){
int i,maxi,maxfd,listenfd,connfd,sockfd;
int nready,client[FD_SETSIZE];
ssize_t n;
fd_set rset,allset;
char buf[MAXLINE];
socklen_t clilen;
struct sockaddr_in servaddr,cliaddr;
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(13);
Bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
Listen(listenfd,1024);
maxfd=listenfd;
maxi=-1;
for(i=0;i<FD_SETSIZE;i++)
client[i]=-1;
FD_ZERO(&allset);
FD_SET(listenfd,&allset);
for(;;){
rset=allset;
nready=Select(maxfd+1,&rset,NULL,NULL,NULL);
if(FD_ISSET(listenfd,&rset)){
clilen=sizeof(cliaddr);
connfd=Accept(listenfd,(struct sockaddr *)&cliaddr,&clilen);
for(i=0;i<FD_SETSIZE;i++)
if(client[i] < 0){
client[i]=connfd;
break;
}
if(i == FD_SETSIZE)
err_quit("too many clients");
FD_SET(connfd,&allset);
if(connfd > maxfd)
maxfd=connfd;
if(i > maxi)
maxi=i;
if(--nready <= 0)
continue;
}
for(i=0;i<=maxi;i++){
if((sockfd=client[i]) < 0)
continue;
if(FD_ISSET(sockfd,&rset)){
if((n=Read(sockfd,buf,MAXLINE)) == 0){
Close(sockfd);
FD_CLR(sockfd,&allset);
client[i]=-1;
}else
writen(sockfd,buf,n);
if(--nready <= 0)
break;
}
}
}
}