当客户端连接变多时会创建连接相同个数的线程或进程,因此当数值比较大的时候,如果上千个连接,此时线程/进程占用以及CPU在上千个进程/线程之间的调度成本太大,造成性能降低。
I/O多路复用就是通过一种机制实现一个进程可以监视多个描述符。相比之下I/O多路复用能够减少系统开销。
代码:
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<string>
#include<cstring>
#include<unistd.h>
#include<errno.h>
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
const int MAXCLINE=5;
int fd[MAXCLINE];
int conn_amount;
void showClient();
int main(int argc ,char * argv[]){
int sockFd,newFd;
sockFd=socket(AF_INET,SOCK_STREAM,0);
if(sockFd<0){
perror("Create socket failed!");
return -1;
}
sockaddr_in raddr,saddr;
int size=sizeof(sockaddr_in);
saddr.sin_family=AF_INET;
saddr.sin_addr.s_addr=inet_addr(argv[1]);
saddr.sin_port=htons(atoi(argv[2]));
char on=1;
setsockopt(sockFd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
int ret=bind(sockFd,reinterpret_cast<sockaddr*>(&saddr),size);
if(ret<0){
perror("Bind Failed!");
exit(-1);
}
ret=listen(sockFd,MAXCLINE);
if(ret<0){
perror("listen failed");
exit(-1);
}
char rbuf[1024]={0};
fd_set fdsr;
timeval tv;
int maxsock=sockFd;
int val=sizeof(sockaddr);
while(1){
//初始化文件描述符集合
FD_ZERO(&fdsr);
FD_SET(sockFd,&fdsr);
//超时
tv.tv_sec=30;
tv.tv_usec=0;
//添加活动的连接
for(int i=0;i<MAXCLINE;i++){
if(fd[i]!=0)
FD_SET(fd[i],&fdsr);
}
//如果文件描述符中有连接请求,会做出相应的处理
ret=select(maxsock+1,&fdsr,nullptr,nullptr,&tv);
if(ret<0){
perror("select error\n");
break;
}
else if(ret==0){
puts("time out");
continue;
}
//循环判断有效的连接是否有数据到达
for(int i=0;i<conn_amount;i++){
if(FD_ISSET(fd[i],&fdsr)){
ret=recv(fd[i],rbuf,sizeof(rbuf)-1,0);
close(fd[i]);
FD_CLR(fd[i],&fdsr);
fd[i]=0;
conn_amount--;
}
else {
if(ret<1024)
memset(&rbuf[ret],'\0',1);
printf("client[%d] send :%s \n",i,rbuf);
send(fd[i],rbuf,sizeof(rbuf)-1,0);
}
}
//有新的连接过来
if(FD_ISSET(sockFd,&fdsr)){
newFd=accept(sockFd,reinterpret_cast<sockaddr*>(&raddr)
,reinterpret_cast<socklen_t*>(&val));
if(newFd<0){
perror("accept failed");
continue;
}
//添加新的fd到数组中,判断有效的连接数是否小于最大连接数
//如果小于最大连接数就将其加入数组中
if(conn_amount<MAXCLINE){
for(int i=0;i<MAXCLINE;i++){
if(fd[i]==0){
fd[i]=newFd;
break;
}
}
conn_amount++;
printf("New connection client[%d]%s:%d\n",
conn_amount,inet_ntoa(raddr.sin_addr),ntohs(raddr.sin_port));
if(newFd>=maxsock){
maxsock=newFd;
}
}
//最大连接数达到,舍弃新连接
else {
printf("max connetcions arrive ,exit\n");
send(newFd,"bye",4,0);
close(newFd);
continue;
}
}
showClient();
}
//活动结束将所有连接断开
for(int i=0;i<MAXCLINE;i++){
if(fd[i]!=0)
close(fd[i]);
}
return 0;
}
void showClient(){
int i;
printf("client amount:%d \n",conn_amount);
for(int i=0;i<MAXCLINE;i++)
printf("[%d]:%d ",i,fd[i]);
printf("\n\n");
}