linux底下epoll模型服务端写数据到客户端?
- C/C++ code
#include <iostream>#include <sys/epoll.h>#include <time.h>#include <sys/time.h>#include <sys/select.h>#include <sys/shm.h>#include <sys/sem.h>#include <sys/types.h>#include <sys/wait.h>#include <sys/stat.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <errno.h>#include <stdio.h>#include <string.h>#include <stdlib.h>#include <signal.h>#include <unistd.h>#include <fcntl.h>#include <stdarg.h>using namespace std;#define MAX_CONNECTED_NO 6#define BUF_SIZE 512#define LISTEN_PORT 10000#define LOCAL_IP 127.0.0.1#define MAX_EVENTS 5#define ERR_EXIT(m) do \{ \ perror(m); \ exit(EXIT_FAILURE); \} while(0)int main(){ int clientArry[20]; for (int i = 0; i < 20; i++) { clientArry[i] = -1; } char acReadBuf[BUF_SIZE] = {0}; char acWriteBuf[BUF_SIZE] = {0}; int listenFd = socket(AF_INET, SOCK_STREAM, 0); if(listenFd == -1) { ERR_EXIT("创建监听端口失败!\n"); } int clientFd = -1; struct sockaddr_in serverAddr; memset(&serverAddr, 0x00, sizeof(struct sockaddr_in)); struct sockaddr_in clientAddr; memset(&clientAddr, 0x00, sizeof(struct sockaddr_in)); socklen_t addrlen; //初始化服务端套接字结构体 serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(LISTEN_PORT); serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); //设置端口复用 int yes = 1; int rlt = setsockopt(listenFd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); if(rlt == -1) { ERR_EXIT("设置端口复用失败!\n"); } //1.2非阻塞模式 int flags = fcntl(listenFd, F_GETFL); fcntl(listenFd, F_SETFL, flags| O_NONBLOCK); //绑定 rlt = bind(listenFd, (struct sockaddr *)(&serverAddr), sizeof(struct sockaddr_in)); if(rlt == -1) { ERR_EXIT("绑定失败!\n"); } //监听 rlt = listen(listenFd, 5); if(rlt == -1) { ERR_EXIT("监听失败!\n"); } //声明epoll_event结构体的变量,ev用于注册事件,数组用于回传要处理的事件 struct epoll_event ev; struct epoll_event events[20]; //生成用于处理accept的epoll专用的文件描述符 int epfd=epoll_create(256); //注册监听的事件 ev.data.fd = listenFd; ev.events=EPOLLIN|EPOLLET|EPOLLOUT; rlt = epoll_ctl(epfd, EPOLL_CTL_ADD, listenFd, &ev); if(rlt == -1) { ERR_EXIT("注册事件失败!\n"); } struct timeval outtime; memset(&outtime, 0x00, sizeof(struct timeval)); while(true) { outtime.tv_sec = 10; outtime.tv_usec = 0; //等待事件发生 int nfds = epoll_wait(epfd, events, MAX_EVENTS,-1); if(nfds == -1) { perror("wait error!\n"); continue; } else if(nfds == 0) { printf("outtime .. \n"); continue; } else { for (int i = 0; i < nfds; i++) { if(events[i].data.fd == listenFd) //监听端口事件触发 { memset(&clientAddr, 0x00, sizeof(struct sockaddr_in)); clientFd = accept(listenFd, (struct sockaddr*)(&clientAddr), &addrlen); if(clientFd == -1) { perror("accept error!\n"); continue; } else { //设置client为非阻塞 int flags = fcntl(clientFd, F_GETFL); fcntl(clientFd, F_SETFL, flags| O_NONBLOCK); //注册client ev.data.fd = clientFd; ev.events = EPOLLIN | EPOLLET|EPOLLOUT; epoll_ctl(epfd, EPOLL_CTL_ADD, clientFd, &ev); printf("one connect is accepted, %s\n", inet_ntoa(clientAddr.sin_addr)); clientArry[i] = clientFd; //保存客户端套接字 } } else if(events[i].events&EPOLLIN)//读取数据 { clientFd = events[i].data.fd; if(clientFd == -1) { continue; } while (true) { rlt = read(clientFd, acReadBuf, sizeof(acReadBuf)); if(rlt < 0) //客户端异常断开 { if(errno == EAGAIN) //无数据,但连接存在 { break; } else { printf("%d clientFd close\n", clientFd); break; } } else if(rlt == 0) //客户端正常断开 { close(clientFd); printf("%d clientFd close\n", clientFd); ev = events[i]; epoll_ctl(epfd, EPOLL_CTL_DEL, clientFd, &ev); break; } else { printf("clientFd %d:\t%s\n ", clientFd, acReadBuf); memset(&acReadBuf, 0x00, sizeof(acReadBuf)); } } } else if(events[i].events&EPOLLOUT) { clientFd = events[i].data.fd; if(clientFd == -1) { continue; } while (true) { rlt = read(0, acWriteBuf, sizeof(acWriteBuf)); if(rlt == -1) { perror("read error!\n"); continue; } rlt = write(events[i].data.fd, acWriteBuf, sizeof(acWriteBuf)); if(rlt == -1) { perror("write error!\n"); continue; } printf("write succese!\n"); } } } } //关闭 } close(listenFd); close(epfd);}
程序代码如上,如何实现能让服务端循环的写入数据到所有客户端,我现在的程序,虽然可以从服务端循环的写入数据到客户端,但是程序死在写入数据的循环中了,出不来,服务端从客户端读取的数据无法到屏幕显示,求教如何能使服务端和客户端之间循环的读取和写入数据。
[解决办法]
你这行有没有逻辑错误:
clientArry[i] = clientFd; //保存客户端套接字
另外,你自己写了个死循环不停的写,有什么办法呢!你每次只写一条数据啊,因为你外面的大循环是一起在循环的,所以还是等于不停的读写,只是读写交错一下。
[解决办法]
读写是个死循环,就有问题了。
应该在 events[i].events&EPOLLIN 下面读,
在 events[i].events&EPOLLOUT 下面写,
而后
ev.events=EPOLLIN|EPOLLET;
epoll_ctl(epfd, EPOLL_CTL_MOD, clientFd, &ev) 重置事件为继续读数据,重复上面的过程