网络异步IO编程:epoll

学习记录,epoll方法网络IO通信 服务器端 IO驱动型写法

一、监听端口

int socket_fd = socket(AF_INET, SOCK_STREAM, 0);

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

serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons(8888);

if (-1 == bind(socket_fd, (struct sockaddr*)&serveraddr, sizeof(struct sockaddr))) {
	perror("bind");
	return -1;
}

listen(socket_fd, 10);

二、相关结构体类型和函数解析

1.epoll_create函数

extern int epoll_create (int __size) __THROW;

作用:在内核建立一个事件表用来存储监视的socket和事件,返回文件描述符。所以后面epoll_wait函数不用将所有监视的socket传入传出内核。

2.epoll_event结构体类型

typedef union epoll_data
{
  void *ptr;
  int fd;
  uint32_t u32;
  uint64_t u64;
} epoll_data_t;

struct epoll_event
{
  uint32_t events;	/* Epoll events */
  epoll_data_t data;	/* User data variable */
} __EPOLL_PACKED;
uint32_t events: 事件类型
epoll_data_t data: 文件描述符或文件指针

3.epoll_ctl函数
对内核中的监视事件表进行添加、删除和修改操作的函数。

extern int epoll_ctl (int __epfd, int __op, int __fd,
		      struct epoll_event *__event) __THROW;
int __epfd: 进行修改的监视事件表
int __op: 要进行的操作,有添加、删除和修改,对应
	添加: EPOLL_CTL_ADD
	删除: EPOLL_CTL_DEL
	修改: EPOLL_CTL_MOD
int __fd: 要添加、删除或者修改的socket
struct epoll_event *__event: 绑定的事件,删除操作设置为NULL

4.epoll_wait函数
监视事件表是否有就绪socket,返回已就绪socket数量,并修改__events数组存储就绪的epoll_event

extern int epoll_wait (int __epfd, struct epoll_event *__events,
		       int __maxevents, int __timeout);
int __epfd: 进行监视的事件表
struct epoll_event *__events: 内核中存储已就绪的epoll_event数组
int __maxevents: 监听的最大数量
int __timeout: 超时时间ms

三、建立事件表和用来返回就绪epoll_event的数组

//建立事件表
int epoll_fd = epoll_create(1);
//定义epoll_wait进行返回就绪epoll_event的数组
struct epoll_event events[1024] = {0};

四、将监听端口的socket添加到监听事件表

struct epoll_event levent;
levent.data.fd = socket_fd;
levent.events = EPOLLIN;

epoll_ctl(epoll_fd, EPOLL_CTL_ADD, socket_fd, &levent);

五、while循环epoll_wait并处理事件

以下为while循环体中的内容

1.epoll_wait监听事件表

int n_ready = epoll_wait(epoll_fd, events, 1024, -1);

2.根据返回的就绪socket数量对events中的事件进行处理,如果是监听socket就添加连接,如果是其它socket的epollin事件就进行通信

for(int i = 0; i < n_ready; i++){
	int fd = events[i].data.fd;
	
	if(fd == socket_fd){
	    sockaddr_in client_addr;
	    socklen_t len = sizeof(client_addr);
	
	    int new_socket = accept(socket_fd, (sockaddr*)&client_addr, &len);
	    printf("accept new socket connect, index: %d\n", new_socket);
	    
	    struct epoll_event temp;
	    temp.data.fd = new_socket;
	    temp.events = EPOLLIN;
	
	    epoll_ctl(epoll_fd, EPOLL_CTL_ADD, new_socket, &temp);
	}
	else if(events[i].events & EPOLLIN){
	    char message[64] = {0};
		if(0 == recv(fd, message, 64, 0)){
		printf("client index %d disconnect.\n", i);
	        
	    epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, NULL);
		close(fd);
		
		continue;
	}
	
	printf("received message from client index %d, context: %s\n", fd, message);
	strcpy(message, "Hello");
	send(fd, message, 64, 0);
	}
	
}

六、完整代码

#include <sys/socket.h>
#include <errno.h>
#include <netinet/in.h>

#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include <pthread.h>
#include <sys/poll.h>
#include <sys/epoll.h>
#include <sys/select.h>

int main() {

	int socket_fd = socket(AF_INET, SOCK_STREAM, 0);

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

	serveraddr.sin_family = AF_INET;
	serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
	serveraddr.sin_port = htons(8888);

	if (-1 == bind(socket_fd, (struct sockaddr*)&serveraddr, sizeof(struct sockaddr))) {
		perror("bind");
		return -1;
	}

	listen(socket_fd, 10);

    //建立事件表
    int epoll_fd = epoll_create(1);
    //定义epoll_wait进行返回就绪epoll_event的数组
    struct epoll_event events[1024] = {0};

    struct epoll_event levent;
    levent.data.fd = socket_fd;
    levent.events = EPOLLIN;

    epoll_ctl(epoll_fd, EPOLL_CTL_ADD, socket_fd, &levent);

    while(1){
        int n_ready = epoll_wait(epoll_fd, events, 1024, -1);

        for(int i = 0; i < n_ready; i++){
            int fd = events[i].data.fd;

            if(fd == socket_fd){
                sockaddr_in client_addr;
                socklen_t len = sizeof(client_addr);

                int new_socket = accept(socket_fd, (sockaddr*)&client_addr, &len);
                printf("accept new socket connect, index: %d\n", new_socket);
                
                struct epoll_event temp;
                temp.data.fd = new_socket;
                temp.events = EPOLLIN;

                epoll_ctl(epoll_fd, EPOLL_CTL_ADD, new_socket, &temp);
            }
            else if(events[i].events & EPOLLIN){
                char message[64] = {0};
				if(0 == recv(fd, message, 64, 0)){
					printf("client index %d disconnect.\n", i);
                    
                    epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, NULL);
					close(fd);

					continue;
				}

				printf("received message from client index %d, context: %s\n", fd, message);
				strcpy(message, "Hello");
				send(fd, message, 64, 0);
            }


        }

    }
	

}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值