非阻塞recv
EAGAIN、EWOULDBLOCK错误码值11
返回值 | 含义 |
---|---|
>0 | 接收字节数 |
0 | 接收FIN包,连接被对端断开 |
-1 | (errno==EAGAIN||EWOULDBLOCK)表示还有数据未读。反之,则表示发生了错误。 |
//epollServer.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <errno.h>
#include <vector>
#include <time.h>
#include <sys/epoll.h>
#include <fcntl.h>
#define MAXEVENTS 100
int InitServer(const unsigned int port);
int setnoblocking(int fd) {
int flags = fcntl(fd, F_GETFL, 0);
if (flags == -1) {
return -1;
}
flags |= O_NONBLOCK;
if (fcntl(fd, F_SETFL, flags) == -1) {
return -1;
}
return 0;
}
bool addfd(int epollfd, int fd, struct epoll_event* ev)
{
memset(ev,0,sizeof(struct epoll_event));
ev->data.fd=fd;
ev->events=EPOLLIN;
//setnoblocking(fd);
return 0==epoll_ctl(epollfd,EPOLL_CTL_ADD,fd,ev); //添加到epollfd
}
bool addfdET(int epollfd, int fd, struct epoll_event* ev)
{
memset(ev,0,sizeof(struct epoll_event));
ev->data.fd=fd;
ev->events=EPOLLIN|EPOLLET;
setnoblocking(fd);
return 0==epoll_ctl(epollfd,EPOLL_CTL_ADD,fd,ev); //添加到epollfd
}
int main(int argc,char** argv)
{
int listenfd=InitServer(atoi(argv[1]));
printf("listenfd=%d\n",listenfd);
if(listenfd==-1)
{
printf("InitServer failed..\n");
return -1;
}
//创建epoll句柄
int epollfd=epoll_create(1);
if(epollfd<0) printf("epoll_create failed..\n");
//epoll_event封装listenfd和监视类型为有数据可读(EPOLLIN)
struct epoll_event ev;
addfd(epollfd, listenfd, &ev);
while(true)
{
struct epoll_event events[MAXEVENTS]; //epoll_wait返回时保存发生的事件
int infds=epoll_wait(epollfd,events,MAXEVENTS,-1);
if(infds<0)
{
printf("epoll_wait failed..\n");
break;
}
if(infds==0)
{
printf("timeout..\n");
break;
}
//发生的事件再events中从index=0依次保存
for(int i=0;i<infds;i++)
{
//listenfd上有数据可读事件发生
if((events[i].data.fd==listenfd) && (events[i].events&EPOLLIN))
{
struct sockaddr_in client_addr;
socklen_t client_addr_size=sizeof(client_addr);
int clientfd = accept(listenfd, (struct sockaddr*)&client_addr,&client_addr_size);
if(clientfd<0)
{
printf("accept failed..\n");
continue;
}
//连接上的客户端添加进监视
//边缘触发
addfdET(epollfd,clientfd,&ev);
continue;
}
else if(events[i].events&EPOLLIN) //有数据可读事件
{
//边缘触发:这段代码不会被epoll_wait重复触发,所以需要手动循环读取直到数据读完。因为循环recv,不能设为阻塞
while(true)
{
char buf[1024];
memset(buf,0,sizeof(buf));
int isize = recv(events[i].data.fd,buf,sizeof(buf),0);
if(isize==0) //连接被对端关闭
{
printf("对端关闭连接\n");
memset(&ev,0,sizeof(struct epoll_event));
ev.data.fd=events[i].data.fd;
ev.events=EPOLLIN;
epoll_ctl(epollfd,EPOLL_CTL_DEL,events[i].data.fd,&ev);
close(events[i].data.fd);
printf("%ld client(%d) disconneted..\n",time(0),events[i].data.fd);
break;
}
else if(isize==-1) //数据未读完或发生错误
{
if((errno==EAGAIN) || (errno==EWOULDBLOCK)) //数据未读完
{
continue; //继续循环执行recv
}
else
{
//错误,终止recv循环
break;
}
}
printf("client(%d)recv msg:%s,size=%d\n",events[i].data.fd,buf,isize); //recv返回值>0
//判断sockfd是否可写
fd_set tmpfd;
FD_ZERO(&tmpfd);
FD_SET(events[i].data.fd,&tmpfd);
if(select(events[i].data.fd+1,0,&tmpfd,0,0)<0)
{
printf("没有可写数据的fd\n");
break;
}
if(write(events[i].data.fd,buf,strlen(buf))<0) //发送
{
printf("write failed..\n");
close(events[i].data.fd);
break;
}
}
}
}
}
return 0;
}
int InitServer(const unsigned int port)
{
int sockfd=-1;
sockfd = socket(PF_INET, SOCK_STREAM, 0);
if(sockfd == -1) return -1;
int opt=1;
unsigned int len=sizeof(opt);
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, len);
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family=AF_INET;
server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
server_addr.sin_port=htons(port);
if(bind(sockfd, (struct sockaddr*) &server_addr, sizeof(server_addr)) == -1)
{
close(sockfd);
sockfd=-1;
return -1;
}
if(listen(sockfd, 5) == -1)
{
close(sockfd);
sockfd=-1;
return -1;
}
return sockfd;
}
标签:ev,epoll,int,编程,epollfd,fd,Linux,include
From: https://www.cnblogs.com/wk2522466153/p/18310241