epoll是TCP/IP网络编程的IO服用方法之中一种优于select的函数,相比select,它有两个优点:
1.无需编写以监视状态变化为目的的针对所有文件描述符的循环语句。
2.调用对应于select函数的epoll_wait函数时无需每次传递监视对象信息。
下面介绍epoll服务器端实现中需要的三个函数,希望各位结合epoll函数的优点理解这些函数的功能。
epoll_create:创建保存epoll文件描述符的空间。
epoll_ctl:向空间注册并注销文件描述符。
epoll_wait:等待文件描述符发生变化。
此外还需要一种结构体:epoll_event将发生变化的文件描述符单独集中到一起。
struct epoll_event{
__unint32_t events;
epoll_data_t data;
}
用法:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<sys/epoll.h>
void error_handling(char *message);
#define BUFF_SIZE 100
#define EPOLL_SIZE 30
int main(int argc, char *argv[])
{
int sock_server;
int sock_client;
struct sockaddr_in addr_server;
struct sockaddr_in addr_client;
socklen_t size_addr_client;
char buff[BUFF_SIZE];
int str_len, i;
int epfd, count_event;
struct epoll_event *ep_events;
struct epoll_event event;
if(argc!=2){ //命令行中启动服务程序仅限一个参数:端口号
printf("Usage : %s <port>\n", argv[0]);
exit(1);
}
//调用socket函数创建套接字
sock_server = socket(PF_INET, SOCK_STREAM, 0);
if(-1 == sock_server){
error_handling("socket() error.");
}
memset(&addr_server, 0, sizeof(addr_server));
addr_server.sin_family = AF_INET;
addr_server.sin_addr.s_addr = htonl(INADDR_ANY);
addr_server.sin_port = htons(atoi(argv[1]));
//调用bind函数分配IP地址和端口号
if( -1 == bind( sock_server, (struct sockaddr*)&addr_server,
sizeof(addr_server)) ){
error_handling("bind() error");
}
//监听端口的连接请求,连接请求等待队列size为5
if( -1 == listen(sock_server, 5) ){
error_handling("listen() error");
}
//epoll
epfd = epoll_create(EPOLL_SIZE);
//epfd = epoll_create(0); //epoll_wait() Error
ep_events = (struct epoll_event*)malloc(sizeof(struct epoll_event)*EPOLL_SIZE);
event.events = EPOLLIN;//监视需用读取数据事件
event.data.fd=sock_server;
epoll_ctl(epfd, EPOLL_CTL_ADD, sock_server, &event);
//
while(1){
count_event = epoll_wait(epfd, ep_events, EPOLL_SIZE, -1);
if(count_event == -1){
puts("epoll_wait() Error");
break;
}
for(i=0; i<count_event; i++){
if(ep_events[i].data.fd == sock_server){
//接受连接请求
size_addr_client = sizeof(addr_client);
sock_client = accept( sock_server, (struct sockaddr*)&addr_client, &size_addr_client);
event.events = EPOLLIN;
event.data.fd = sock_client;
epoll_ctl(epfd, EPOLL_CTL_ADD, sock_client, &event);
printf("Connected client : %d\n", sock_client);
}else{
str_len = read(ep_events[i].data.fd, buff, BUFF_SIZE);
if(str_len){//echo to client
buff[str_len] = 0;
printf("Message from client %d: %s", i, buff);
write(ep_events[i].data.fd, buff, str_len);//echo!
}else{ //close connection
epoll_ctl(epfd, EPOLL_CTL_DEL, ep_events[i].data.fd, NULL);
close(ep_events[i].data.fd);
printf("Disconnected client %d!\n", ep_events[i].data.fd);
}
}//end of if()
}//end of while
}//end of for
//断开连接,关闭套接字
close(sock_server);
close(epfd);//
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(EXIT_FAILURE);
}