上一节讲了select , poll。
但是现代的linux系统对于多路富用采用的更多为epoll函数。
epoll比前两个函数更加好用,下面给出具体用法。
void server6(){
const uint16_t listened_port=9000;
const char* localhost="127.0.0.1";
const int listening_queue_length=1024;
const int buffersize=1024;
int listen_fd=socket(AF_INET,SOCK_STREAM,0);
sockaddr_in server_addr,client_addr;
socklen_t len;
bzero(&server_addr,sizeof(server_addr));
server_addr.sin_family=AF_INET;
in_addr temp;
inet_pton(AF_INET,localhost,&server_addr.sin_addr);
server_addr.sin_port=htons(listened_port);
bind(listen_fd,(const sockaddr*)&server_addr,sizeof(server_addr));
listen(listen_fd,listening_queue_length);
char buf[buffersize];
epoll_event ev,events[20];
int epoll_fd=epoll_create(1024);
ev.data.fd=listen_fd;
ev.events=EPOLLIN|EPOLLET;
if(epoll_ctl(epoll_fd,EPOLL_CTL_ADD,listen_fd,&ev)<0){
cerr<<"error in epoll_ctl "<<endl;
exit(1);
}
int nfds;
while(1){
nfds=epoll_wait(epoll_fd,events,20,-1);
cout<<"event number ->"<<nfds<<endl;
for(int i=0;i<nfds;++i){
if(events[i].data.fd==listen_fd){
int connect_fd=accept(listen_fd,(sockaddr*)&client_addr,&len);
if(connect_fd<0){
cerr<<"error in connect..."<<endl;
continue;
}
cout<<"get connection..."<<endl;
printf("client info :%s\n",inet_ntoa(client_addr.sin_addr));
ev.data.fd=connect_fd;
ev.events=EPOLLIN|EPOLLET;
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, connect_fd, &ev);
}
else if(events[i].events&EPOLLOUT){
cout<<"fd is writeable.("<<events[i].data.fd<<")"<<endl;
int newfd=events[i].data.fd;
if(newfd<0){
cout<<"new fd<0"<<endl;
continue;
}
const char* hello="hi client";
int f=write(events[i].data.fd,hello,strlen(hello));
if(f<0){
cerr<<"write error.."<<endl;
}
cout<<"write message ok.."<<endl;
ev.data.fd=events[i].data.fd;
ev.events=EPOLLOUT|EPOLLET;
epoll_ctl(epoll_fd,EPOLL_CTL_DEL,events[i].data.fd,&ev);
}
else if(events[i].events&EPOLLIN){
cout<<"fd is readable.("<<events[i].data.fd<<")"<<endl;
int new_fd=events[i].data.fd;
if(new_fd<0){
cout<<"new-fd<0"<<endl;
continue;
}
int n;
if((n=read(new_fd,buf,buffersize))<0){
if(errno==ECONNRESET){
close(new_fd);
events[i].data.fd=-1;
cerr<<"ECONNRESET.."<<endl;
}
else{
cerr<<"read buffer error"<<endl;
}
}
else if(n==0){
close(new_fd);
events[i].data.fd=-1;
cout<<"read 0 bytes"<<endl;
}
cout<<"get message:"<<buf<<endl;
ev.data.fd=events[i].data.fd;
ev.events=EPOLLOUT|EPOLLET;
epoll_ctl(epoll_fd,EPOLL_CTL_MOD,new_fd,&ev);
}
}
}
}
这里面epoll_ctl可以加入/修改/删除一个监听事件。epoll_create可以创建一组监听对象。逻辑思想和poll和select倒是很像。