epoll详解(三)-- ET模式实例
2016-06-23 23:00
435 查看
通过本文你会了解到:
1. 非阻塞预备知识点
2. 非阻塞server源码
3. 运行测试(应用linux 的 nc 工具)
非阻塞预备知识点
在非阻塞socket编程时,为保证兼容性问题,最好同时判断
非阻塞server源码
约定
格式为 /**/ 的注释对程序的主要流程进行解释
格式为 // 的注释对程序做必要的说明
运行测试
linux中nc是一个强大的网络工具,本文只用nc来创建一个socket客户端,来测试epoll server,如果想深入了解nc可以参考linux
nc创建客户端命令:
接入server:
当接入server后输入数据并回车即可向server发送数据。
测试截图:
1. 非阻塞预备知识点
2. 非阻塞server源码
3. 运行测试(应用linux 的 nc 工具)
非阻塞预备知识点
O_NONBLOCK- 应用于socket描述符时,另之后对此描述符的阻塞操作(如read/write等)变为非阻塞。
EAGAIN- 表示没有可用数据,稍后再试。产生此错误的前提条件是socket描述符为非阻塞时(即,设置为
O_NONBLOCK标志)。在VxWorks和Windows上,EAGAIN的名字叫做EWOULDBLOCK。
在非阻塞socket编程时,为保证兼容性问题,最好同时判断
EAGAIN和
EWOULDBLOCK标志。
非阻塞server源码
约定
格式为 /**/ 的注释对程序的主要流程进行解释
格式为 // 的注释对程序做必要的说明
#include <stdio.h> // for printf() #include <stdlib.h> // for exit() #include <unistd.h> // for read() and write() #include <sys/epoll.h> // for epoll #include <sys/socket.h> // for epoll #include <netinet/in.h> //struct sockaddr_in #include <string.h> // memset #include <fcntl.h> // fcntl #include <errno.h> // errno #define EPOLL_QUEUE_LEN 32 //监听的最大连接数 #define BUF_SIZE 1024 static int set_nonblocking(int fd) { int flags; flags = fcntl(fd, F_GETFL, 0); if(flags == -1) { perror("fcntl"); return -1; } flags |= O_NONBLOCK; if(fcntl(fd, F_SETFL, flags) == -1) { perror("fcntl"); return -1; } return 0; } static int listen_socket(int port) { int fd; struct sockaddr_in sa; fd = socket(AF_INET, SOCK_STREAM, 0); if(fd == -1) { perror("socket"); return -1; } memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; sa.sin_port = htons(port); sa.sin_addr.s_addr = htonl(INADDR_ANY); if(bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) { perror("bind"); close(fd); return -1; } if(set_nonblocking(fd) == -1) { close(fd); return -1; } if(listen(fd, 5) == -1) { perror("listen"); close(fd); return -1; } return fd; } int main(int argc, char **argv) { struct epoll_event ev; struct epoll_event events[EPOLL_QUEUE_LEN]; int epfd; int sfd; int nfds; if(argc != 2) { printf("usage: %s [port]\n", argv[0]); exit(EXIT_FAILURE); } /*创建 epoll 实例*/ epfd = epoll_create(EPOLL_QUEUE_LEN); if(epfd == -1) { perror("epoll_create"); exit(EXIT_FAILURE); } /*对输入port进行监听*/ printf("server listen form port: %d\n", atoi(argv[1])); sfd = listen_socket(atoi(argv[1])); if(sfd == -1) { printf("listen_socket failed\n"); exit(EXIT_FAILURE); } /*将server描述符添加到epoll中*/ ev.data.fd = sfd; ev.events = EPOLLIN | EPOLLET; if(epoll_ctl(epfd, EPOLL_CTL_ADD, sfd, &ev) == -1) { perror("epoll_ctl"); exit(EXIT_FAILURE); } /*主循环*/ while(1) { int i; /*等待epoll实例中描述符有I/O事件发生*/ nfds = epoll_wait(epfd, events, EPOLL_QUEUE_LEN, -1); for(i = 0; i < nfds; i++) { if(events[i].events & (EPOLLERR | EPOLLHUP)) { //EPOLLERR - 出现错误 //EPOLLHUP - 客户端提前关闭连接(close by peer) continue; } if(!(events[i].events & EPOLLIN)) { //不是IN操作 continue; } if(sfd == events[i].data.fd) { /*有客户端连入server*/ struct sockaddr_in in_addr; socklen_t in_len; int infd; while(1) { //非阻塞操作accept需要循环检测 infd = accept(sfd, (struct sockaddr *)&in_addr, &in_len); if(infd == -1) { if(errno == EAGAIN || errno == EWOULDBLOCK) { ///已接收到所有描述符 break; } else { perror("accept"); break; } } if(set_nonblocking(infd) == -1) { break; } ev.data.fd = infd; ev.events = EPOLLIN | EPOLLET; if(epoll_ctl(epfd, EPOLL_CTL_ADD, infd, &ev) == -1) { perror("epoll_ctl"); exit(EXIT_FAILURE); } printf("incoming client [fd=%d]\n", infd); } } else { /*收到客户端数据*/ int done = 0; while(1) { ssize_t cnt; char buf[BUF_SIZE]; memset(buf, 0, sizeof(buf)); cnt = read(events[i].data.fd, buf, sizeof(buf)); if(cnt == -1) { if(errno == EAGAIN) { done = 1; break; } else { perror("read"); } } else if (cnt == 0) { //fd 被关闭 done = 1; break; } printf("receive data: %s\n", buf); } if(done == 1) { printf("close client [fd=%d]\n", events[i].data.fd); close(events[i].data.fd); } } } } close(sfd); return 0; }
运行测试
linux中nc是一个强大的网络工具,本文只用nc来创建一个socket客户端,来测试epoll server,如果想深入了解nc可以参考linux
man nc。
nc创建客户端命令:
接入server:
nc ip port- ip 为server的IP地址 prot为server的端口
当接入server后输入数据并回车即可向server发送数据。
测试截图:
相关文章推荐
- Seafile Server本地权限提升漏洞(CVE-2014-5443)
- 从USB安装Ubuntu Server 10.04.3 图文详解
- 使用zabbix监控Nginx活动状态--Part1
- 高效访问Internet-启用ISA Server的缓存
- windows server域用户提升到本地更高权限组中的方法
- 完美解决SQL Server 安装问题:以前的某个程序安装已在安装计算机上创建挂起的文件操作
- IIS 错误 Server Application Error 详细解决方法
- 在WINXP系统上安装SQL Server企业版的方法
- SQL Server 存储过程的分页
- 交换机升级排障实例
- SQL Server复制需要有实际的服务器名称才能连接到服务器
- SQL Server 2000向SQL Server 2008 R2推送数据图文教程
- SQL server 表操作介绍
- SQL Server 2000 注入防护大全(二)
- SQL Server 2000 注入防护大全(一)
- 怎样把Windows server 2003转换成工作站系统
- Windows Server 2007四月CTP发布 下载
- IIS运行错误 Server Application Error 错误代码 Error: 8004的解决方法
- Microsoft SQL Server 2008安装图解教程(Windows 7)
- ASP基础入门第十篇(ASP内建对象Server)