系统提供select函数来实现多路复⽤用输⼊入/输出模型。select系统调⽤用是⽤用来让我们的程序监视 多个⽂文件句柄的状态变化的。程序会停在select这⾥里等待,直到被监视的⽂文件句柄有⼀一个或 多个发⽣生了状态改变
int select(int nfds,fd_set * readfds,fd_set*writefds,fd_set*exceptfds,struct timeval*timeout)
(1)参数nfds是需要监视的最⼤大的⽂文件描述符值+1; (2)rdset,wrset,exset分别对应于需要检测的可读⽂文件描述符的集合,可写⽂文件描述符的集 合及异 常⽂文件描述符的集合。 struct timeval结构⽤用于描述⼀一段时间长度,如果在这个时间内,需要监视的描述符没有事件 发⽣生则函数返回,返回值为0。 下⾯面的宏提供了处理这三种描述词组的⽅方式: FD_CLR(inr fd,fd_set* set);⽤用来清除描述词组set中相关fd 的位 FD_ISSET(int fd,fd_set *set);⽤用来测试描述词组set中相关fd 的位是否为真 FD_SET(int fd,fd_set*set);⽤用来设置描述词组set中相关fd的位 FD_ZERO(fd_set *set);⽤用来清除描述词组set的全部位 参数timeout为结构timeval,⽤用来设置select()的等待时间,其结构定义如下
struct timeval{
long tv_sec;
long tv_usec;
}
(3)如果参数timeout设为: NULL:则表⽰示select()没有timeout,select将⼀一直被阻塞,直到某个⽂文件描述符上发⽣生了 事件。 0:仅检测描述符集合的状态,然后⽴立即返回,并不等待外部事件的发⽣生。 特定的时间值:如果在指定的时间段⾥里没有事件发⽣生,select将超时返回。 函数返回值: 执⾏行成功则返回⽂文件描述词状态已改变的个数 如果返回0代表在描述词状态改变前已超过timeout时间,没有返回; 当有错误发⽣生时则返回-1,错误原因存于errno,此时参数readfds,writefds,exceptfds和 timeout的值变成不可预测。错误值可能为: EBADF ⽂文件描述词为⽆无效的或该⽂文件已关闭 EINTR 此调⽤用被信号所中断 EINVAL 参数n 为负值。 ENOMEM 核⼼心内存不⾜
3,代码:
服务器端:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc,char* argv[])
{
if(argc!=3)
{
printf("Usage: %s[server_ip][server_port]\n",argv[0]);
exit(1);
}
int sock=socket(AF_INET,SOCK_STREAM,0);
if(sock<0)
{
perror("socket");
exit(2);
}
struct sockaddr_in server;
server.sin_family=AF_INET;
server.sin_port=htons(atoi(argv[2]));
server.sin_addr.s_addr=inet_addr(argv[1]);
int c=connect(sock,(struct sockaddr*)&server,sizeof(server));
if(c>0)
{
printf("please Enter#");
fflush(stdout);
dup2(1,sock);
printf("server Echo#");
dup2(sock,1);
}
return 0;
}
服务器端
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int StatUp(char*ip,int port)
{
int sock=socket(AF_INET, SOCK_STREAM, 0);
if(sock<0)
{
perror("socket");
exit(2);
}
struct sockaddr_in local;
local.sin_addr.s_addr=inet_addr(ip);
local.sin_port=htons(port);
socklen_t len=sizeof(local);
int b=bind(sock,(struct sockaddr*)&local,len);
if(b<0)
{
perror("bind");
exit(3);
}
int l=listen(sock,10);
if(l<0)
{
perror("listen");
exit(4);
}
return sock;
}
int main(int argc,char* argv[])
{
int newfile=open("./test1",O_CREAT|O_RDWR,0666);
if(argc!=3)
{
printf("Usger:%s [server_ip][server_port]",argv[0]);
exit(1);
}
int listen_sock=StatUp(argv[1],atoi(argv[2]));
int r_arr[10];
int i;
for(i=0;i<10;i++)
{
r_arr[i]=-1;
}
fd_set rfds;
r_arr[0]=listen_sock;
while(1)
{
FD_ZERO(&rfds);
int max_fd=-1;
struct timeval timeout={5,0};
for(i=0;i<10;i++)
{
if(r_arr[i]>0)
{
FD_SET(r_arr[i],&rfds);
if(max_fdswitch( select(max_fd+1,&rfds,NULL,NULL,NULL))
{
case 0:
printf("time out\n");
break;
case -1:
perror("select");
break;
default:
{
int j,k;
struct sockaddr_in client;
socklen_t len=sizeof(client);
for( j=0;j<10;j++)
{
if(j==0 && FD_ISSET(r_arr[j],&rfds))
{
int newsock=accept(listen_sock,(struct sockaddr*)&client,&len);
if(newsock>0)
{
printf("get client\n");
for(i=0;i<10;i++)
{
if(r_arr[i]<0)
{
r_arr[i]=newsock;
break;
}
}
if(i==10)
close(newsock);
}//accept success
else
{
perror("accept");
continue;
} //accept false
} //is listen
else if(j>0 && FD_ISSET(r_arr[j],&rfds))
{
char buf[1024];
int s=read(r_arr[j],buf,sizeof(buf)-1);
if(s==0)
{
printf("file is close");
fflush(stdout);
close(r_arr[j]);
r_arr[j]=-1;
}
else if(s>0)
{
buf[s-1]=0;
// fflush(stdout);
printf("read file:%s\n",buf);
fflush(stdout);
}
else
{
perror("read");
break;
}
}//isn"t listen sock
}//for j
// int k;
for(k=0;k<10;k++) //resolve write
{
if(w_arr[k]<0)
continue;
char * p="I'am server! hello";
if(FD_ISSET(w_arr[k],&wfds))
{
write(w_arr[k],p,strlen(p));
close(w_arr[k]);
w_arr[k]=-1;
}
} //for k
}//default
break;
}//swith
}//while
return 0;
}