首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 操作系统 > UNIXLINUX >

linux下部epoll模型服务端写数据到客户端

2013-03-26 
linux底下epoll模型服务端写数据到客户端?本帖最后由 VisualEleven 于 2012-10-08 21:25:51 编辑#include

linux底下epoll模型服务端写数据到客户端?
本帖最后由 VisualEleven 于 2012-10-08 21:25:51 编辑

#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) 重置事件为继续读数据,重复上面的过程

热点排行
Bad Request.