(五)epoll实现TCP服务端
来源:互联网 发布:剑三明星捏脸数据 编辑:程序博客网 时间:2024/06/11 22:08
1.epoll是由poll改进而来的。
2.epoll跟poll在编程实现上有一定程度相似。
3.epoll主要通过结构体 epoll_event 来实现监听。
(!!!!!!不想看原理的可以直接拉到后面看代码!!!!!)
//epoll_event结构体struct epoll_event { uint32_t events; /* Epoll events */ epoll_data_t data; /* User data variable */ } __attribute__ ((__packed__)); typedef union epoll_data { void *ptr; int fd; uint32_t u32; uint64_t u64; } epoll_data_t;
虽然我知道贴出来可能都没卵用,我还是直接说吧。epoll编程的几个步骤:
1.创建 epoll_event 类型的结构体2个, 如: struct epoll_event events,wait_events 前者是用于把套接字描述符加到 epoll句柄中的,后者是用于判断发生了什么事件
struct epoll_event event; //用于往epoll句柄中加入新的需要监测的套接字
struct epoll_event wait_event; //用于装epoll_wait()的返回信息,判断哪一个套接字发生响应
2.用 epoll_create()创造一个 epoll句柄:
int epfd = epoll_create(10); //这个10没什么大概意义,只要是正整数即可。
3.给结构体epoll_event 赋值并加入到 epoll句柄 epfd中。epoll_ctl()
event.data.fd = sockfd; //sockfd为 socket()函数返回的监听套接字
event.events = EPOLLIN; //设置期望该套接字发生的事件为可读事件
epoll_ctl(epfd,EPOLL_CTL_ADD,sockfd,&event); //EPOLL_CTL_ADD表示往epfd中加入新的套接字来检测
4.等待套接字响应。epoll_wait()
int ret = epoll_wait(epfd,&wait_event,num,-1);
//解释一下上面的这个函数:
第一个参数:epoll句柄(由epoll_create()返回的)
第二个参数:struct epoll_event 类型的结构体,放在该位置,当epoll_wait返回时,就会把响应的套接字信息放到这个结构体中。
第三个参数:正在监测的套接字个数。
第四个参数:-1表示一直阻塞直到有套接字发生响应,0表示不阻塞,无论有没有套接字响应 都返回,>0表示阻塞的时间,毫秒为单位。
这个函数的返回值ret 为发生响应的套接字的个数。
5.判断epfd中哪个套接字发生响应
if((wait_event.data.fd == sockfd)&&(wait_event.events & EPOLLIN ==EPOLLIN)) //若套接字sockfd发生响应,并且为可读
{......}
下面给出代码:
服务端:
#include "myhead.h"#define MAX 50void write_to_all(char *wbuf); //此函数用于把一个客户端发来的消息转发给其他客户端int client_fd[50]; //此数组用于装连接进来的客户端的套接字文件描述符int main(){int sockfd,newsockfd;struct sockaddr_in saddr;int size = sizeof(struct sockaddr_in);//创建2个epoll_event结构体struct epoll_event event;//用于往epoll句柄加入新的待检测套接字struct epoll_event wait_event; //用于装epoll_wait()返回的响应的套接字的消息,判断哪个套接字发生响应int on = 1;int ret;//设置TCP套接字的一些属性bzero(&saddr,size);saddr.sin_family = AF_INET;saddr.sin_port = htons(8888);saddr.sin_addr.s_addr = htonl(INADDR_ANY);sockfd = socket(AF_INET,SOCK_STREAM,0);setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));//设置端口复用,不设也可以,对功能没影响bind(sockfd,(struct sockaddr*)&saddr,sizeof(struct sockaddr));listen(sockfd,10);//epoll 相关参数int max = 0;memset(client_fd,-1,sizeof(client_fd));int epfd;//创建epoll句柄epfdepfd = epoll_create(10); //这是10没啥意义,只要是正数即可。//加入监听套接字event.data.fd = sockfd;event.events = EPOLLIN;epoll_ctl(epfd,EPOLL_CTL_ADD,sockfd,&event);//加入标准输入,使服务端可以发信息event.data.fd = 0;event.events = EPOLLIN;epoll_ctl(epfd,EPOLL_CTL_ADD,0,&event);int i;while(1){//等待套接字发生某种响应,否则一直阻塞ret = epoll_wait(epfd,&wait_event,max+2,-1);//判断是否有新客户端连入if((wait_event.data.fd ==sockfd) && (wait_event.events &EPOLLIN == EPOLLIN)){int len = sizeof(struct sockaddr);struct sockaddr_in caddr;newsockfd = accept(sockfd,(struct sockaddr*)&caddr,&len);//newsockfd加入client_fdfor(i=0;i<MAX;i++){if(client_fd[i] != -1)continue;else{client_fd[i] = newsockfd;break;}}//newsockfd加入epoll句柄 epfdevent.data.fd = newsockfd;event.events = EPOLLIN;epoll_ctl(epfd,EPOLL_CTL_ADD,newsockfd,&event);max+=1;ret --;//处理完一个响应后,ret减一if(ret<=0)//若ret已经为0,则说明已经处理完所有的发生响应的套接字,就可以继续epoll_wait()等待套接字发生再响应{continue;}}if((wait_event.data.fd ==0)&&(wait_event.events & EPOLLIN==EPOLLIN)){char wbuf[50]={0};bzero(wbuf,50);scanf("%s",wbuf);write_to_all(wbuf);ret-=1;}//判断有没有其他客户端的数据发来for(i=0;i<MAX;i++){char rbuf[50]={0};if((wait_event.data.fd ==client_fd[i])&&(wait_event.events&EPOLLIN==EPOLLIN)){int recv_num;bzero(rbuf,50);recv_num = recv(client_fd[i],rbuf,50,0);if(recv_num == 0){client_fd[i] = -1;close(client_fd[i]);max -=1;}else{printf("%s\n",rbuf);bzero(rbuf,50);}ret-=1;if(ret<=0)break;}}}}void write_to_all(char *wbuf){int i;for(i=0;i<MAX;i++){if(client_fd[i] !=-1){write(client_fd[i],wbuf,50);}}}
客户端:
客户端有很多种写法,这里就给出一种用poll写的,因为也懒得再写,就用之前用开的客户端代码:
#include"myhead.h"char rbuf[50];char wbuf[50];char ipbuf[50];int main(){int sockfd;int ret,port;struct pollfd pollfd[2];struct sockaddr_in saddr;int size = sizeof(struct sockaddr_in);bzero(&saddr,size);saddr.sin_family = AF_INET;saddr.sin_port = htons(8888);saddr.sin_addr.s_addr = inet_addr("192.168.152.128");sockfd = socket(AF_INET,SOCK_STREAM,0);ret=connect(sockfd,(struct sockaddr*)&saddr,sizeof(struct sockaddr));if(ret == 0){inet_ntop(AF_INET,(void*)&saddr.sin_addr.s_addr,ipbuf,50);port = ntohs(saddr.sin_port);printf("%s,%d\n",ipbuf,port);}pollfd[0].fd = STDIN_FILENO;pollfd[0].events = POLLIN;pollfd[1].fd = sockfd;pollfd[1].events = POLLIN;while(1){poll(pollfd,2,-1);if((pollfd[0].revents & POLLIN)==POLLIN){puts("message from keyboard");bzero(wbuf,50);scanf("%s",wbuf);write(sockfd,wbuf,50);}if((pollfd[1].revents & POLLIN)==POLLIN){bzero(rbuf,50);read(sockfd,rbuf,50);printf("%s\n",rbuf);}}}
0 0
- (五)epoll实现TCP服务端
- 实现TCP并发服务器之五(epoll函数)
- epoll服务端代码实现
- epoll实现服务端异步通信
- epoll实现TCP通信
- (四) 用poll实现TCP服务端
- (六)多进程实现TCP服务端
- 使用epoll实现TCP多路复用
- Python用epoll实现简易HTTP服务端
- python使用epoll实现的服务端例子
- python使用epoll实现的服务端例子
- WinSock客户端服务端实现--TCP
- node.js tcp服务端实现
- TCP通讯(服务端)
- Socket的实现,服务端和客户端(TCP)
- 客户端与服务端的TCP通信实现(Qt)
- python用epoll方式实现客户端对服务端发起大量连接(短连接)
- python用epoll方式实现客户端对服务端发起大量连接(长连接)
- android-----关于通过AIDL注册监听之后无法解除监听的探索
- 亚马逊的人工智能音箱卷入了一起谋杀案
- JSONP操作03_jsonp是什么
- 学习小结
- Android中ListView的几种常见的优化方法
- (五)epoll实现TCP服务端
- java-JDBC-ResultSet详解(java数据库操作)
- opencv学习三种常用方法访问操作图像像素
- sublime3安装配置找寻到的有用资料
- 浅谈Mac OS下SVN的使用方法(下)
- iptables规则的删除-怎么删除一条已有的iptables规则
- 测试
- 基于TI-RTOS的CC2650DK开发(26)--- LCD官方示例
- 【原创】简单尝试脱“爱加密”官网加固的DEX壳