网络编程学习(七)_epoll编程实例

一、Epoll模型的三个函数

int epoll_create(int size);

作用:创建一个epoll句柄,告诉他需要监听的数目(也可以理解成申请一片空间,用于存放监听的套接字)
参数一:通知内核监听size个fd,只是个建议值并与硬件有关系。(从 Linux 内核 2.6.8 版本起,size 这个参数就被忽略了,只要求 size 大于 0 即可)
返回值:返回epoll句柄(fd)

*int epoll_ctl(int epfd, int op, int fd, struct epoll_event event);

作用:控制某个epoll监控的文件描述符上的事件:注册,修改、删除(也就是增添 删除 修改一个事件)
参数一:int epfd:epoll_create()的返回值

参数二:int op: 表示动作,用三个宏来表示
EPOLL_CTL_ADD(注册新的fd到epfd)
EPOLL_CTL_MOD(修改已经注册的fd监听事件)
EPOLL_CTL_DEL(从epfd删除一个fd)

参数三:int fd 操作对象(socket)

参数四:struct epoll_evevt* evevt; 告诉内核需要监听的事件

结构体如下:
struct epoll_event {
__uint32_t events; 宏定义读和写EPOLLIN读EPOLLOUT写
epoll_data_t data; 联合体
};
联合体如下:

typedef union epoll_data {
void *ptr;
int fd;
__uint32_t u32;
__uint64_t u64;
} epoll_data_t;

返回值:成功返回0,不成功返回-1

int epoll_wait(int epfd,struct epoll_event * events,int maxevents,int timeout)

作用:监听红黑树上的事件,将产生动静的事件放在event这个数组内
参数一:int epfd:epoll_create()函数返回值

参数二:struct epoll_events* events用于回传代处理事件的数组(也就是存放产生动静的事件)

参数三:int maxevents 同时最多产生多少事件,告诉内核events有多大,该值必须大于0

参数四:int timeout表示 -1相当于阻塞,0相当于非阻塞,超时时间(单位:毫秒)

返回值:成功返回产生动静事件的个数

二、简单demo

sever.c

#include <stdio.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>

#define OPEN_MAX 1024  //最多连接数

int main(int argc, char *argv[])
{
    int listenfd = socket(AF_INET, SOCK_STREAM, 0);

    int on = 1;
    int i;
    int connfd;
    setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));//设置为可重复使用的端口

    struct sockaddr_in serv_addr; //服务器的地址结构体
    memset(&serv_addr,0,sizeof(serv_addr));

    //设置本服务器要监听的地址和端口,这样客户端才能连接到该地址和端口并发送数据
    serv_addr.sin_family = AF_INET;                //选择协议族为IPV4
    serv_addr.sin_port = htons(9000);         //绑定我们自定义的端口号,客户端程序和我们服务器程序通讯时,就要往这个端口连接和传送数据
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); //监听本地所有的IP地址;INADDR_ANY表示的是一个服务器上所有的网卡(服务器可能不止一个网卡)多个本地ip地址都进行绑定端口号,进行侦听。

    bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));

    listen(listenfd, 32);

    int efd = epoll_create(OPEN_MAX);

    struct epoll_event event, events[OPEN_MAX];
    event.events=EPOLLIN|EPOLLET;
    event.data.fd = listenfd;

    epoll_ctl(efd, EPOLL_CTL_ADD, listenfd, &event);//把服务器fd包装成事件放在红黑树上

    while(1)
    {
        int nready=epoll_wait(efd,events,OPEN_MAX,-1);//判断为可读事件
        for(i=0; i<nready; i++)
        {
            if(!(events[i].events & EPOLLIN))
            {
                continue;
            }

            if(events[i].data.fd == listenfd)//表示有新的连接
            {
                struct sockaddr_in client_addr;
                int len=sizeof(client_addr);
                memset(&client_addr,0,sizeof(client_addr));
                connfd = accept(listenfd, (struct sockaddr *)&client_addr, &len);
 				event.events = EPOLLIN|EPOLLET; 
				event.data.fd = connfd;  
				epoll_ctl(efd, EPOLL_CTL_ADD, connfd, &event);               
            }
            else//表示旧的数据产生可读事件(1 客户端发来数据 2 客户端断开链接)
            {
     			connfd=events[i].data.fd;
				char recvline [1024];
				memset(recvline,0,1024);	
                int nread=read(connfd,recvline,sizeof(recvline));
				if(nread==0)
				{
					printf("client is close..\n"); //打印
					epoll_ctl(efd, EPOLL_CTL_DEL, connfd, NULL);//删除果子 select是从集合 和 数组 删除
					close(connfd);//关闭客服端 select一样
                }
				else
				{
					printf("%s",recvline);
				}			
            }
        }
    }

    return 0;    
}

client.c

#include <stdio.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);

    struct sockaddr_in serv_addr;
    memset(&serv_addr, 0, sizeof(serv_addr));

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(9000);

    if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0)
    {
        printf("inet_pton failed exit !\n");
        exit(1);
    }

    if(connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
    {
        printf("connect() failed exit!\n");
        exit(1);        
    }

    int len;
    char recvline[1024]; 
    char writeline[1024];

    while(1)
    {
        memset(recvline, 0, sizeof(recvline));
        memset(writeline, 0, sizeof(writeline));

        //发送消息
		printf("send to server:");
		fgets(writeline,sizeof(writeline),stdin);
		write(sockfd,writeline,strlen(writeline));

        len = read(sockfd,recvline,1024);

        if(len == 0)
        {
            printf("server is close");
        }

        printf("receive from server:%s\n",recvline);
    }

    close(sockfd); //关闭套接字
    printf("end exit !\n");
    return 0;     

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值