一、select、poll、epoll区别
从上一个博客的代码可以看到:
select提供一个fd_set类型的集合来存储监听事件;
poll则是用struct pollfd来存储监听事件,struct pollfd中有:所管理事件的文件描述符fd、所关心的事件类型events(比如POLLIN),输出行参数revents(通知用户事件的就绪状态);
可以看到上面两个都是需要遍历事件集合来判断事件是否就绪,而且事件集合的个数也有一定限制,epoll的高效主要体现再epoll_wait,原因在于epoll_wait的返回值:当返回值大于0时,是告诉当前用户的就绪事件个数,并且把这写事件按照顺序从头排列到用户提供的events里(红黑树存储),这样就不用遍历了,
而且epoll有两种出发方式:LT水平触发(有就绪事件就一直通知,最好将当前IO设置为非阻塞的),ET边沿触发(只有新的事件到来时才会通知,高效)
二、应用实例
1.epoll
-
#include<stdio.h>
-
#include<unistd.h>
-
#include<sys/types.h>
-
#include<sys/socket.h>
-
#include<netinet/in.h>
-
#include<arpa/inet.h>
-
#include<sys/epoll.h>
-
#include<fcntl.h>
-
#include<stdlib.h>
-
#include<string.h>
-
-
int creat_socket(char *ip,char* port)
-
{
-
int sock = socket(AF_INET,SOCK_STREAM,0);
-
if(sock < 0){
-
perror("socket");
-
exit(2);
-
}
-
-
//调用setsockopt使当server先断开时避免进入TIME_WAIT状态,\
-
将其属性设定为SO_REUSEADDR,使其地址信息可被重用
-
int opt = 1;
-
if(setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt)) < 0){
-
perror("setsockopt");
-
exit(3);
-
}
-
-
struct sockaddr_in local;
-
-
local.sin_family = AF_INET;
-
local.sin_port = htons(atoi(port));
-
local.sin_addr.s_addr = inet_addr(ip);
-
-
if( bind(sock,(struct sockaddr*)&local,sizeof(local)) < 0 ){
-
perror("bind");
-
exit(4);
-
}
-
-
if(listen(sock,5) < 0){
-
perror("listen");
-
exit(5);
-
}
-
-
printf("listen and bind succeed\n");
-
-
return sock;
-
}
-
-
int set_noblock(int sock)
-
{
-
int fl = fcntl(sock,F_GETFL);
-
return fcntl(sock,F_SETFL,fl|O_NONBLOCK);
-
}
-
-
int main(int argc,char *argv[])
-
{
-
if(argc != 3){
-
printf("please use:%s [ip] [port]",argv[0]);
-
exit(1);
-
}
-
int listen_sock = creat_socket(argv[1],argv[2]);
-
-
int epoll_fd = epoll_create(256);
-
if(epoll_fd < 0){
-
perror("epoll creat");
-
exit(6);
-
}
-
-
struct epoll_event ep_ev;
-
ep_ev.events = EPOLLIN;//数据的读取
-
ep_ev.data.fd = listen_sock;
-
-
//添加关心的事件
-
if(epoll_ctl(epoll_fd,EPOLL_CTL_ADD,listen_sock,&ep_ev) < 0){
-
perror("epoll_ctl");
-
exit(7);
-
}
-
-
struct epoll_event ready_ev[128];//申请空间来放就绪的事件。
-
int maxnum = 128;
-
int timeout = 1000;//设置超时时间,若为-1,则永久阻塞等待。
-
int ret = 0;
-
-
int done = 0;
-
while(!done){
-
switch(ret = epoll_wait(epoll_fd,ready_ev,maxnum,timeout)){
-
case -1:
-
perror("epoll_wait");
-
break;
-
case 0:
-
printf("time out...\n");
-
break;
-
default://至少有一个事件就绪
-
{
-
int i = 0;
-
for(;i < ret;++i){
-
//判断是否为监听套接字,是的话accept
-
int fd = ready_ev[i].data.fd;
-
if((fd == listen_sock) && (ready_ev[i].events & EPOLLIN)){
-
struct sockaddr_in remote;
-
socklen_t len = sizeof(remote);
-
-
int accept_sock = accept(listen_sock,(struct sockaddr*)&remote,&len);
-
if(accept_sock < 0){
-
perror("accept");
-
continue;
-
}
-
printf("accept a client..[ip]: %s,[port]: %d\n",inet_ntoa(remote.sin_addr),ntohs(remote.sin_port));
-
//将新的事件添加到epoll集合中
-
ep_ev.events = EPOLLIN | EPOLLET;
-
ep_ev.data.fd = accept_sock;
-
-
set_noblock(accept_sock);
-
-
if(epoll_ctl(epoll_fd,EPOLL_CTL_ADD,accept_sock,&ep_ev) < 0){
-
perror("epoll_ctl");
-
close(accept_sock);
-
}
-
}
-
else{//普通IO
-
if(ready_ev[i].events & EPOLLIN){
-
//申请空间同时存文件描述符和缓冲区地址
-
-
char buf[102400];
-
memset(buf,'\0',sizeof(buf));
-
-
ssize_t _s = recv(fd,buf,sizeof(buf)-1,0);
-
if(_s < 0){
-
perror("recv");
-
continue;
-
}else if(_s == 0){
-
printf("remote close..\n");
-
//远端关闭了,进行善后
-
epoll_ctl(epoll_fd,EPOLL_CTL_DEL,fd,NULL);
-
close(fd);
-
}else{
-
//读取成功,输出数据
-
printf("client# %s",buf);
-
fflush(stdout);
-
-
//将事件改写为关心事件,进行回写
-
ep_ev.data.fd = fd;
-
ep_ev.events = EPOLLOUT | EPOLLET;
-
-
//在epoll实例中更改同一个事件
-
epoll_ctl(epoll_fd,EPOLL_CTL_MOD,fd,&ep_ev);
-
}
-
}else if(ready_ev[i].events & EPOLLOUT){
-
const char*msg = "HTTP/1.1 200 OK \r\n\r\n
hi girl
\r\n";
-
send(fd,msg,strlen(msg),0);
-
epoll_ctl(epoll_fd,EPOLL_CTL_DEL,fd,NULL);
-
close(fd);
-
}
-
}
-
}
-
}
-
break;
-
-
}
-
}
-
close(listen_sock);
-
return 0;
-
}
2.poll(跟epoll区别了一下,就不写刚开始的socket了)
-
#include <stdio.h>
-
#include <poll.h>
-
#include <string.h>
-
-
int main()
-
{
-
int timeout = 3000;
-
char buf[1024];
-
struct pollfd fd_poll[1]; //设置只有一个事件
-
-
while(1){
-
fd_poll[0].fd = 0;
-
fd_poll[0].events = POLLIN;
-
fd_poll[0].revents = 0;
-
-
memset(buf, '\0', sizeof(buf));
-
switch( poll(fd_poll, 1, timeout) ){
-
case 0:
-
perror("timeout!");
-
break;
-
case -1:
-
perror("poll");
-
break;
-
default:
-
{
-
if( fd_poll[0].revents & POLLIN ){
-
-
gets(buf);
-
printf("buf : %s\n",buf);
-
}
-
}
-
break;
-
}
-
}
-
return 0;
-
}
阅读(1774) | 评论(0) | 转发(0) |