基于Linux epoll模型的Simple

来源:互联网 发布:手机挡字幕软件 编辑:程序博客网 时间:2024/04/24 16:03

关于epoll的介绍以及与其它I/O模型的优缺点,各大网站论坛均有介绍,这里就不多说了;

本Simple使用了epoll的边缘出发模式(ET),支持多客户端连接;

首先定义自己的数据结构以及相关全局变量:

#define MAX_EVENTS 10#define MAX_BUFFER_SIZE 1024#define LISTEN_PORT 8000struct global_data{int server_sock;int server_epoll;};struct client_data{char *read_buf;char *write_buf;int read_len;int read_off;int write_len;int write_off;int fd;struct sockaddr_in addr;};struct global_data g_gd;
client_data结构体用来存储和处理客户端上下文数据;

下面初始化一个新的客户端上下文结构:

struct client_data *alloc_client_data(int fd, struct sockaddr_in *addr = NULL){struct client_data *cd = NULL;cd = (struct client_data *)malloc(sizeof(struct client_data));if(cd == NULL){return NULL;}memset(cd, 0, sizeof(struct client_data));cd->fd = fd;cd->write_len = MAX_BUFFER_SIZE;cd->write_off = 0;cd->read_len = MAX_BUFFER_SIZE;cd->read_off = 0;cd->write_buf = (char *)malloc(cd->write_len + 1);cd->read_buf = (char *)malloc(cd->read_len + 1);assert(cd->write_buf);assert(cd->read_buf);if(addr) memcpy(&cd->addr, addr, sizeof(cd->addr));return cd;}
释放客户端上下文数据:

void free_client_data(struct client_data *cd){if(cd == NULL) return ;close(cd->fd);if(cd->write_buf) free(cd->write_buf);if(cd->read_buf) free(cd->read_buf);free(cd);return ;}
设置socket为非阻塞模式:

int set_sock_non_block(int fd){int flags, result;flags = fcntl(fd, F_GETFL, 0);if(flags == -1){return -1;}flags |= O_NONBLOCK;result = fcntl(fd, F_SETFL, flags);if(result == -1){return -1;}return 0;}
处理客户端连接请求:

int accept_client(){int ret = -1;int addrlen;int client_sock;struct sockaddr_in remote_addr;struct epoll_event e_event;do{while(1){addrlen = sizeof(struct sockaddr_in);client_sock = accept(g_gd.server_sock, (struct sockaddr *)&remote_addr, (socklen_t *)&addrlen);if(client_sock == -1){if(errno == EAGAIN || errno == EWOULDBLOCK){break;}else{printf("accept failed, error: %s \n", strerror(errno));break;}}else{set_sock_non_block(client_sock);struct client_data *cd = alloc_client_data(client_sock, &remote_addr);assert(cd);e_event.events = EPOLLIN | EPOLLET;e_event.data.ptr = cd;if(epoll_ctl(g_gd.server_epoll, EPOLL_CTL_ADD, client_sock, &e_event) == -1){printf("epoll_ctl client failed \n");free_client_data(cd);}else{printf("accept client: %s:%d \n", inet_ntoa(remote_addr.sin_addr), ntohs(remote_addr.sin_port));}}}ret = 0;}while(0);return ret;}
接收客户端数据:

int recv_data(struct client_data *client){int ret = -1;int len_recv = 0;struct epoll_event e_event;if(client == NULL) return -1;do{while(1){len_recv = recv(client->fd, client->read_buf, client->read_len, 0);if(len_recv == -1){if(errno == EAGAIN){break;}else{free_client_data(client);break;}}else if(len_recv == 0){printf("client closed connection!!! \n");free_client_data(client);break;}else{client->read_buf[len_recv] = '\0';printf("[%s:%d] recv data: %s:%d \n", inet_ntoa(client->addr.sin_addr), ntohs(client->addr.sin_port),client->read_buf,len_recv);client->read_off = len_recv;// send responsestrcpy(client->write_buf, "OK!");client->write_off = strlen(client->write_buf);e_event.events = EPOLLOUT | EPOLLET;e_event.data.ptr = client;epoll_ctl(g_gd.server_epoll, EPOLL_CTL_MOD, client->fd, &e_event);}}ret = 0;}while(0);return ret;}
发送数据给客户端:

int send_data(struct client_data *client){int ret = -1;int len_send = 0;struct epoll_event e_event;if(client == NULL) return -1;do{len_send = send(client->fd, client->write_buf, client->write_off, 0);if(len_send == -1){if(errno != EAGAIN){printf("send error %s \n", strerror(errno));free_client_data(client);}}else if(len_send == 0){free_client_data(client);}else{e_event.events = EPOLLIN | EPOLLET;e_event.data.ptr = client;epoll_ctl(g_gd.server_epoll, EPOLL_CTL_MOD, client->fd, &e_event);}ret = 0;}while(0);return ret;}
服务器主程:

void epoll_server(){int len_recv;int len_send;int len_sin;int signal_count;struct sockaddr_in local_addr;struct epoll_event e_event;struct epoll_event e_events[MAX_EVENTS];char buff[MAX_BUFFER_SIZE];memset(&g_gd, '\0', sizeof(struct global_data));memset(buff, '\0', sizeof(buff));do{// create server socketg_gd.server_sock = socket(AF_INET, SOCK_STREAM, 0);if(g_gd.server_sock < 0){printf("create socket failed \n");break;}// bindlocal_addr.sin_family = AF_INET;local_addr.sin_addr.s_addr = INADDR_ANY;local_addr.sin_port = htons(LISTEN_PORT);if(bind(g_gd.server_sock, (struct sockaddr *)&local_addr, sizeof(local_addr)) == -1 ){printf("bind socket failed \n");break;}// set non-blockif(set_sock_non_block(g_gd.server_sock) == -1){printf("set_sock_non_block failed \n");break;}// listenif(listen(g_gd.server_sock, SOMAXCONN) == -1){printf("listen fialed \n");break;}// create epoll handleg_gd.server_epoll = epoll_create(MAX_EVENTS);if(g_gd.server_epoll < 0){printf("epoll create failed \n");break;}// register server socket evente_event.events = EPOLLIN | EPOLLET;e_event.data.fd = g_gd.server_sock;if(epoll_ctl(g_gd.server_epoll, EPOLL_CTL_ADD, g_gd.server_sock, &e_event) < 0){printf("epoll_ctl failed \n");break;}while(1){printf("epoll wait... \n");signal_count = epoll_wait(g_gd.server_epoll, e_events, MAX_EVENTS, -1);if(signal_count == -1){ printf("epoll_wait failed \n"); break; }printf("wait signals: %d \n", signal_count);for(int i=0; i<signal_count; ++i){if(e_events[i].events & EPOLLERR || e_events[i].events & EPOLLHUP){printf("socket error occured \n");continue;}else if(e_events[i].data.fd == g_gd.server_sock){accept_client();}else if(e_events[i].events & EPOLLIN){recv_data((struct client_data *)e_events[i].data.ptr);}else if(e_events[i].events & EPOLLOUT){send_data((struct client_data *)e_events[i].data.ptr);}else{printf("Some error happend \n");}}}}while(0);close(g_gd.server_sock);close(g_gd.server_epoll);return ;}









0 0
原创粉丝点击