网络编程(10)基于epoll的服务器实现
2014-02-16 23:21
281 查看
关于epoll的相关知识我不就写了,只把我弄的例子写下,我整的这个epoll服务器其实就只是把man epoll中举得那个例子给做完善了。
主要参考了man epoll和百度百科中关于epoll的介绍来实现的。
服务器代码:
代码中用到的头文件在<<网络编程(1)跨平台的Socket同步阻塞工作模式例子>>
MAIL: xcl_168@aliyun.com
BLOG: http://blog.csdn.net/xcl168
主要参考了man epoll和百度百科中关于epoll的介绍来实现的。
服务器代码:
/************************************************* Author: xiongchuanliang Description: 基于epoll的服务器,就是把man epoll中的例子补充完整了。 编译命令: Linux: g++ -o tcpepoll2 tcpepoll2.cpp -m64 -I./common **************************************************/ // 服务端代码 #include <stdio.h> #include <stdlib.h> #include <string.h> #include "initsock.h" #include "common.h" #include <sys/epoll.h> CInitSock initSock; #define MAX_EVENTS 10 int do_use_fd(int client); //与客户端交互 int setnonblocking(int sock); // 设置套接字为不阻塞 int main(int argc, char* argv[]) { int n = 0; //创建套接字 SOCKET sListen = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); if(sListen == INVALID_SOCKET) { PrintError("socket() failed.\n"); exit(EXIT_FAILURE); } //绑定本地IP和端口到套接字 struct sockaddr_in server_addr; server_addr.sin_family = AF_INET; server_addr.sin_port = htons(SERVPORT); //大于1024且小于65535 server_addr.sin_addr.s_addr = INADDR_ANY; bzero(&(server_addr.sin_zero),8); //SO_REUSEADDR : 使bind函数能允许地址立即重用 int on = 1; setsockopt( sListen, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on) ); if(bind(sListen,(struct sockaddr *)&server_addr,sizeof(struct sockaddr)) == SOCKET_ERROR) { PrintError("bind() failed."); exit(EXIT_FAILURE); } //开始监听 if(listen(sListen, BACKLOG) == SOCKET_ERROR) { PrintError("sListen() failed."); exit(EXIT_FAILURE); } struct epoll_event ev,events[MAX_EVENTS]; SOCKET conn_sock, nfds, epollfd; //listen_sock //指定内核需要监听的描述数 //函数原型:int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); epollfd = epoll_create(10); if (epollfd == -1) { PrintError("epoll_create"); exit(EXIT_FAILURE); } /* EPOLLLT 默认行为,只要一个文件描述符处于就绪状态,epoll 就会不停的通知你有事件发生。传统的 select/poll 都是这样处理。 EPOLLET 属新方式,只在一个文件描述符新处于就绪的时候通知一次,之后不管数据有没有读完,都不会再通知,当然,有新数据到还是会通知的。 所以,用 EPOLLET 的时候,一定要把文件描述符设置为 non-blocking, 而且最好是一直读数据,读到返回 EAGAIN 才停下 */ //指定内核需要监听的事件,并注册一个新的fd到epoll_create()返回的epollfd中 ev.events = EPOLLIN | EPOLLET; //对读感兴趣,边沿触发模式 ev.data.fd = sListen; //函数原型:int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); if (epoll_ctl(epollfd, EPOLL_CTL_ADD, sListen, &ev) == -1) { PrintError("epoll_ctl: listen_sock"); exit(EXIT_FAILURE); } socklen_t nAddrlen = sizeof(struct sockaddr_in); for (;;) { //函数原型: int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout); //MAX_EVENTS的值不能大于 epoll_create()指定的值 //等待epoll_ctl指定的监听的事件发生 nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1); if (nfds == -1) { <span style="white-space:pre"> </span>continue; // PrintError("epoll_pwait()"); } //遍历发生了指定监听的事件事件的fd for (n = 0; n < nfds; ++n) { // 如果是主socket的事件的话,则表示 // 有新连接进入了,进行新连接的处理。 if (events .data.fd == sListen) { //连接指定的客户端 // conn_sock = accept(sListen,(struct sockaddr *) &local, &addrlen); conn_sock = accept(sListen,(struct sockaddr *) &server_addr, &nAddrlen); if (conn_sock == -1) { PrintError("accept()"); continue; } // 将新连接设置为非阻塞模式 setnonblocking(conn_sock); //设置event为监控读操作,即客户端有发送数据过来。 ev.events = EPOLLIN | EPOLLET; ev.data.fd = conn_sock; //将新设置的这个event加入到epoll的监听队列里 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock, &ev) == -1) { PrintError("epoll_ctl: conn_sock"); } }else{ do_use_fd(events .data.fd); } } //end for (n = 0; n < nfds; ++n) } //end for (;;) //关闭监听套接字 close(sListen); //关闭epoll句柄 close(epollfd); exit(EXIT_SUCCESS); } //与客户端交互 int do_use_fd(int client) { char recvData[MAXDATASIZE]={0}; int recvbytes = read(client,recvData, MAXDATASIZE); if( recvbytes == 0) { printf("read() no data!\n"); }else if( recvbytes < 0) { if (errno != EAGAIN) { PrintError("read() failed."); close (client); } }else if( recvbytes > 0) { recvData[recvbytes]='\0'; printf("msg:%s\n",recvData); char sendData[MAXDATASIZE]={0}; strcpy(sendData,"Hello client!\n"); int sendbytes = write(client, sendData, sizeof(sendData)) ; if( sendbytes < 0) { PrintError("write() failed."); close (client); }else{ printf("write() success! %d \n",sendbytes); } } } // 设置套接字为不阻塞 int setnonblocking(int sock) { int flags = fcntl (sock, F_GETFL, 0); if (flags == -1) { PrintError("fcntl() failed."); return -1; } flags |= O_NONBLOCK; if ( (fcntl (sock, F_SETFL, flags)) == -1) { PrintError("fcntl() failed. O_NONBLOCK"); return -1; } return 0; }
代码中用到的头文件在<<网络编程(1)跨平台的Socket同步阻塞工作模式例子>>
MAIL: xcl_168@aliyun.com
BLOG: http://blog.csdn.net/xcl168
相关文章推荐
- 基于 epoll 实现 web 服务器
- 基于 epoll 实现 web 服务器
- 基于epoll实现简单的web服务器
- 基于 epoll 实现 web 服务器
- 基于epoll实现的一个简单web服务器
- 分享:基于epoll实现的一个简单的web服务器
- 基于 epoll 实现 web 服务器
- 基于 epoll 实现 web 服务器
- 基于 epoll 实现 web 服务器
- 基于 epoll 实现 web 服务器
- 基于 epoll 实现 web 服务器
- 基于 epoll 实现 web 服务器
- 基于 epoll 实现 web 服务器
- 分享:基于epoll实现的一个简单的web服务器
- 基于 epoll 实现 web 服务器
- 基于HTTP协议实现的小型web服务器
- 基于TCP协议用多线程实现并发服务器,实现思路、算法和demo
- 基于ARM的嵌入式web服务器的设计与实现
- [C# 网络编程系列]专题十一:实现一个基于FTP协议的程序——文件上传下载器
- 基于git和intotify实现的git提交服务器自动更新的功能