?? epoll_t.cc
字號:
#include <iostream>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#define MAXLINE 10
#define OPEN_MAX 100
#define LISTENQ 20
#define SERV_PORT 5555
#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);
}
}
// 發(fā)送數(shù)據(jù)
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)
{
// 當(dāng)send收到信號時,可以繼續(xù)寫,但這里返回-1.
if(errno == EINTR)
{
return -1;
}
// 當(dāng)socket是非阻塞時,如返回此錯誤,表示寫緩沖隊列已滿,
// 在這里做延時后再重試.
if(errno == EAGAIN)
{
usleep(1000);
continue;
}
return -1;
}
if((size_t)tmp == total)
{
return buflen;
}
total -= tmp;
p += tmp;
}
return tmp;
}
int main()
{
int i, maxi, listenfd, connfd, sockfd, epfd, nfds;
ssize_t rs, n = 0;
char line[MAXLINE];
int l_sinSize = 0;
l_sinSize = sizeof(struct sockaddr);
// 聲明epoll_event結(jié)構(gòu)體的變量,ev用于注冊事件,數(shù)組用于回傳要處理的事件
struct epoll_event ev, events[20];
// 生成用于處理accept的epoll專用的文件描述符
epfd = epoll_create(256);
struct sockaddr_in clientaddr;
struct sockaddr_in serveraddr;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
// 把socket設(shè)置為非阻塞方式
setnonblocking(listenfd);
// 設(shè)置與要處理的事件相關(guān)的文件描述符
ev.data.fd = listenfd;
// 設(shè)置要處理的事件類型
ev.events = EPOLLIN|EPOLLET;
// 注冊epoll事件
epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev);
bzero(&serveraddr, sizeof(struct sockaddr_in));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons(SERV_PORT);
bind(listenfd, (struct sockaddr *)(&serveraddr), sizeof(struct sockaddr));
listen(listenfd, LISTENQ);
maxi = 0;
for ( ; ; )
{
// 等待epoll事件的發(fā)生
nfds=epoll_wait(epfd,events,20,500);
// 處理所發(fā)生的所有事件
for (i = 0; i < nfds; ++i)
{
if (events[i].data.fd == listenfd)
{
connfd = accept(listenfd, (struct sockaddr *)(&clientaddr), (socklen_t *)&l_sinSize);
if (connfd < 0)
{
perror("connfd < 0");
exit(1);
}
setnonblocking(connfd);
char* str = inet_ntoa(clientaddr.sin_addr);
std::cout<<"connect from "<<str<<std::endl;
// 設(shè)置用于讀操作的文件描述符
ev.data.fd = connfd;
// 設(shè)置用于注測的讀操作事件
ev.events = EPOLLIN|EPOLLET;
// 注冊ev
epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &ev);
}
else if (events[i].events&EPOLLIN)
{
if ((sockfd = events[i].data.fd) < 0)
{
continue;
}
/*
if ((n = read(sockfd, line, MAXLINE)) < 0)
{
if (errno == ECONNRESET)
{
close(sockfd);
events[i].data.fd = -1;
}
else
{
std::cout<<"readline error"<<std::endl;
}
}
else if (n == 0)
{
close(sockfd);
events[i].data.fd = -1;
}
*/
while(rs)
{
n = recv(sockfd, line, MAXLINE, 0);
if(n < 0)
{
// 由于是非阻塞的模式,所以當(dāng)errno為EAGAIN時,表示當(dāng)前緩沖區(qū)已無數(shù)據(jù)可讀
// 在這里就當(dāng)作是該次事件已處理處.
if(errno == EAGAIN)
{
break;
}
else
{
return;
}
}
else if(n == 0)
{
// 這里表示對端的socket已正常關(guān)閉.
}
if(n == sizeof(line))
{
rs = 1; // 未讀完 需要再次讀取
}
else
{
rs = 0;
}
}
//設(shè)置用于寫操作的文件描述符
ev.data.fd = sockfd;
//設(shè)置用于注測的寫操作事件
ev.events = EPOLLOUT|EPOLLET;
//修改sockfd上要處理的事件為EPOLLOUT
epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev);
}
else if(events[i].events&EPOLLOUT)
{
sockfd = events[i].data.fd;
ssize_t l_writeSize = write(sockfd, line, n);
std::cout<<"write "<<l_writeSize<<std::endl;
//設(shè)置用于讀操作的文件描述符
ev.data.fd = sockfd;
//設(shè)置用于注測的讀操作事件
ev.events = EPOLLIN|EPOLLET;
//修改sockfd上要處理的事件為EPOLIN
epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev);
}
}
}
}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -