转自 http://zhouxiaodan.blog.51cto.com/1177793/1176286
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define MAXLINE 512
#define OPEN_MAX 100
#define LISTENQ 20
#define SERV_PORT 9876
#define INFTIM 1000
void setnonblocking(int sock)
{
int opts;
opts=fcntl(sock,F_GETFL);
if(opts<0)
{
perror("fcntl(sock,GETFL)");
exit(1);
}
opts = opts | O_NONBLOCK;
if(fcntl(sock,F_SETFL,opts)<0)
{
perror("fcntl(sock,SETFL,opts)");
exit(1);
}
}
/*
假如发送端流量大于接收端的流量
(意思是epoll所在的程序读比转发的socket要快),
由于是非阻塞的socket,那么send()函数虽然返回,
但实际缓冲区的数据并未真正发给接收端,
这样不断的读和发,
当缓冲区满后会产生EAGAIN错误(参考man send),同时,
不理会这次请求发送的数据.所以,
需要封装socket_send()的函数用来处理这种情况,
该函数会尽量将数据写完再返回,返回-1表示出错。
在socket_send()内部,当写缓冲已满(send()返回-1,且errno为EAGAIN),
那么会等待后再重试.这种方式并不很完美,
在理论上可能会长时间的阻塞在socket_send()内部,
但暂没有更好的办法.
*/
ssize_t socket_send(int sockfd, const char* buffer, size_t buflen)
{
ssize_t tmp;
size_t total = buflen;
const char *p = buffer;
while(1)
{
tmp = send(sockfd, p, total, 0);
if(tmp < 0)
{
// 当send收到信号时,可以继续写,但这里返回-1.
if(errno == EINTR)
//return -1;zxd
continue;
// 当socket是非阻塞时,如返回此错误,表示写缓冲队列已满,
// 在这里做延时后再重试.
if(errno == EAGAIN)
{
usleep(1000);
continue;
}
return -1;
}
if((size_t)tmp == total)
return buflen;
total -= tmp;
p += tmp;
}
return tmp;
}
void epoll_ctl_err_show()
{
std::cout << "error at epoll_ctl" << std::endl;
if(EBADF == errno)
{
std::cout << "error at epoll_ctl, error is EBADF" << std::endl;
}
else if(EEXIST == errno)
{
std::cout << "error at epoll_ctl, error is EEXIST" << std::endl;
}
else if(EINVAL == errno)
{
std::cout << "error at epoll_ctl, error is EINVAL" << std::endl;
}
else if(ENOENT == errno)
{
std::cout << "error at epoll_ctl, error is ENOENT" << std::endl;
}
else if(ENOMEM == errno)
{
std::cout << "error at epoll_ctl, error is ENOMEM" << std::endl;
}
else if(ENOSPC == errno)
{
std::cout << "error at epoll_ctl, error is ENOSPC" << std::endl;
}
}
int main()
{
int i, maxi, listenfd, connfd, sockfd, epfd, nfds;
ssize_t n;
char line[MAXLINE];
socklen_t clilen;
struct epoll_event ev,events[20]; //声明epoll_event结构体的变量, ev用于注册事件, events数组用于回传要处理的事件
epfd=epoll_create(256); //生成用于处理accept的epoll专用的文件描述符, 指定生成描述符的最大范围为256
struct sockaddr_in clientaddr;
struct sockaddr_in serveraddr;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
setnonblocking(listenfd); //把用于监听的socket设置为非阻塞方式
ev.data.fd=listenfd; //设置与要处理的事件相关的文件描述符
ev.events=EPOLLIN | EPOLLET; //设置要处理的事件类型
epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev); //注册epoll事件
bzero(&serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
char *local_addr="127.0.0.1";
inet_aton(local_addr,&(serveraddr.sin_addr));
serveraddr.sin_port=htons(SERV_PORT); //或者htons(SERV_PORT);
bind(listenfd,(sockaddr *)&serveraddr, sizeof(serveraddr));
listen(listenfd, LISTENQ);
maxi = 0;
for( ; ; ) {
nfds=epoll_wait(epfd, events, 20, -1); //等待epoll事件的发生
for(i=0;i 0)
{
setnonblocking(connfd); //把客户端的socket设置为非阻塞方式
char *str = inet_ntoa(clientaddr.sin_addr);
std::cout<<"connect from "< 0)
{
n += nread;
}//读到EAGAIN,说明读完了
if(nread == -1 && errno != EAGAIN)
{
epoll_ctl_err_show();
std::cout<<"readline error"<
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define BUFSIZE 512
#define RET_ERR -1
#define RET_OK 0
#define Debug_UserLog printf
#define Debug_SysLog printf
void SetNonBlock(int fd)
{
int flag = fcntl ( fd, F_GETFL, 0 );
fcntl ( fd, F_SETFL, flag | O_NONBLOCK );
}
int main(int argc, char** argv)
{
int iRet = RET_OK;
if(4 != argc)
{
Debug_UserLog("Parameter: ServerIP Message ServerPort", RET_ERR);
return RET_ERR;
}
in_port_t i16_port = atoi(argv[3]);
if(0 >= i16_port)
{
Debug_UserLog("port number is wrong", RET_ERR);
return RET_ERR;
}
int sk = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(-1 == sk)
{
Debug_SysLog("open socket failed!");
return RET_ERR;
}
struct sockaddr_in sa = {0};
sa.sin_family = AF_INET;
sa.sin_port = htons(i16_port);
struct sockaddr_in *psa = &sa;
iRet = inet_pton(AF_INET, argv[1], &psa->sin_addr.s_addr);
if(0 == iRet)
{
Debug_UserLog("inet_pton failed, invalid address!", RET_ERR);
close(sk);
return RET_ERR;
}
else if(iRet < 0)
{
Debug_SysLog("inet_pton failed");
close(sk);
return RET_ERR;
}
if(connect(sk, (struct sockaddr*)&sa, sizeof(sa)) < 0)
{
Debug_SysLog("connect failed");
close(sk);
return RET_ERR;
}
SetNonBlock(sk);
int efd;
efd = epoll_create(10);
if(efd == -1)
{
perror("epoll_create error!");
exit(1);
}
struct epoll_event event;
struct epoll_event events[10];
event.events = EPOLLOUT | EPOLLIN | EPOLLET;
event.data.fd = sk;
epoll_ctl(efd, EPOLL_CTL_ADD, sk, &event);
getchar();
int loop = 0;
while(1)
{
ssize_t numBytesRcvd = 0;
char buffer[BUFSIZE] = {0};
int n = 0;
int i = 0;
if(loop == 1)
{
break;
}
n = epoll_wait(efd, events, 10, -1);
printf("%d\n", n);
for(i = 0; i < n; i++)
{
if(events[i].events & EPOLLOUT)
{
printf("EPOLLOUT...............\n");
snprintf(buffer, BUFSIZE, "i am process %d, just say: %s\n", getpid(), argv[2]);
int n = strlen(buffer);
int nsend = 0;
while(n > 0)
{
//nsend = send(events[i].data.fd, buffer + nsend, n, 0);
nsend = write(events[i].data.fd, buffer + nsend, n);
if(nsend < 0 && errno != EAGAIN)
{
Debug_SysLog("send failed");
close(events[i].data.fd);
return RET_ERR;
}
n -= nsend;
}
}
if(events[i].events & EPOLLIN)
{
printf("EPOLLIN...............\n");
memset(buffer, 0, BUFSIZE);
int len = strlen(buffer);
int n = 0;
int nrecv = 0;
while(1){
nrecv = read(events[i].data.fd, buffer + n, BUFSIZE - 1) ;
if(nrecv == -1 && errno != EAGAIN)
{
perror("read error!");
}
if((nrecv == -1 && errno == EAGAIN) || nrecv == 0)
{
break;
}
n += nrecv;
}
loop = 1;
printf("%s\n", buffer);
}
}
}
close(sk);
close(efd);
return RET_OK;
}