epoll的非阻塞IO模式,利用边沿触发模式,同时修改read()函数模式为非阻塞读取,这样在减少epoll_wait()函数调用的同时也实现了水平触发的效果,是对epoll最优的模式。
服务器端:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<string.h>
#include<arpa/inet.h>
#include<sys/epoll.h>
#include<errno.h>
#include<ctype.h>
#define MAXLINE 8196
#define SERV_PORT 6666
#define OPEN_MAX 1000
#define SERV_IP "127.0.0.1"
void perr_exit(const char *str)
{
perror(str);
exit(1);
}
int main(int argc,char *argv[])
{
int i,n;
int listenfd,sockfd,connfd;
ssize_t nready,efd,res;
char buf[MAXLINE],str[INET_ADDRSTRLEN];
socklen_t clie_len;
int flag;
struct sockaddr_in clie_addr,serv_addr;
struct epoll_event tep,ep[OPEN_MAX];
listenfd=socket(AF_INET,SOCK_STREAM,0);
int opt=1;
setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));//端口复用
bzero(&serv_addr,sizeof(serv_addr));
serv_addr.sin_family=AF_INET;
//serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
inet_pton(AF_INET,SERV_IP,&serv_addr.sin_addr.s_addr);
serv_addr.sin_port=htons(SERV_PORT);
bind(listenfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));//绑定IP和端口
listen(listenfd,128);
efd=epoll_create(OPEN_MAX);//创建epoll模型,efd指向红黑树根节点
if(efd==-1)
perr_exit("epoll error!");
tep.events=EPOLLIN | EPOLLET; //边沿触发模式
printf("accept connect...\n");
clie_len=sizeof(clie_addr);
connfd=accept(listenfd,(struct sockaddr *)&clie_addr,&clie_len);
printf(" connect client ip:%s---port:%d\n",
inet_ntop(AF_INET,&clie_addr.sin_addr.s_addr,str,sizeof(str)),
ntohs(clie_addr.sin_port)
);
flag=fcntl(connfd,F_GETFL);//修改connfd为非阻塞读
flag |= O_NONBLOCK;
fcntl(connfd,F_SETFL,flag);
//fcntl(connfd,F_SETFL,O_NONBLOCK);另一种写法
tep.data.fd=connfd;
epoll_ctl(efd,EPOLL_CTL_ADD,connfd,&tep);
while(1)
{
printf("***************************************\n");
printf("epoll_wait begin\n");
res=epoll_wait(efd,ep,10,-1);
printf("epoll_wait end %ld\n",res);
if(ep[0].data.fd==connfd)
{
while((n=read(connfd,buf,5))>0) //非阻塞读取,每次读一半数据
write(STDOUT_FILENO,buf,n);
}
}
return 0;
}
客户端:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/socket.h>
#include<ctype.h>
#include<arpa/inet.h>
#include<string.h>
#define SERV_IP "127.0.0.1"
#define SERV_PORT 6666
#define MAXLINE 10
int main()
{
int cfd,sfd;
struct sockaddr_in serv_addr;
socklen_t serv_addr_len;
char buf[MAXLINE],clien_ip[BUFSIZ];
int n,i;
char ch='a';
int res;
memset(&serv_addr,0,sizeof(serv_addr));
serv_addr.sin_family=AF_INET;
serv_addr.sin_port=htons(SERV_PORT);//转换为网络字节序
//serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);//INADDR_ANY可以自行寻找ip
inet_pton(AF_INET,SERV_IP,&serv_addr.sin_addr.s_addr);
cfd=socket(AF_INET,SOCK_STREAM,0);//创建本地套接字
// bind(lfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));//绑定,客户端隐式绑定
res=connect(cfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr) );
if(res==-1)
{
perror("connect error");
exit(1);
}
while(1) //循环发送10个字符
{
printf("**************************************\n");
//aaaa\n
for(i=0;i<MAXLINE/2;i++)
buf[i]=ch;
buf[i-1]='\n';
ch++;
// bbbb\n
for(;i<MAXLINE;i++)
buf[i]=ch;
buf[i-1]='\n';
ch++;
printf("client write--\n");
write(STDOUT_FILENO,buf,sizeof(buf));
write(cfd,buf,sizeof(buf));
sleep(5);
}
close(cfd);
return 0;
}
运行如下: