epoll_socket

背景

通常来说,实现处理tcp请求,为一个连接一个线程,在高并发的场景,这种多线程模型与Epoll相比就显得相形见绌了。epoll是linux2.6内核的一个新的系统调用,epoll在设计之初,就是为了替代select, poll线性复杂度的模型,epoll的时间复杂度为O(1), 也就意味着,epoll在高并发场景,随着文件描述符的增长,有良好的可扩展性。

参考

epoll原理
epoll触发模式
对于触发模式重点,可以总结为下

如果对于一个非阻塞 socket,如果使用 epoll 边缘模式去检测数据是否可读,触发可读事件以后,一定要一次性把 socket 上的数据收取干净才行,也就是说一定要循环调用 recv 函数直到 recv 出错,错误码是EWOULDBLOCK(EAGAIN 一样)(此时表示 socket 上本次数据已经读完);如果使用水平模式,则不用,你可以根据业务一次性收取固定的字节数,或者收完为止

例子

/*************************************************************************
    > File Name: epollsvr.c
    > Author: ycj
    > Mail: 1484541288@qq.com 
    > Created Time: 2024年01月24日 星期三 16时33分07秒
 ************************************************************************/

#include<stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/epoll.h>

#define NAME_LEN 50
#define MAX_CLIENTS 100


int size = 0;

int init_server(const char* ip,unsigned short int port){
   
	
	int fd = socket(AF_INET,SOCK_STREAM,0);
	assert(fd != -1);
	int oldSocketFlag = fcntl(fd,F_GETFL,0);
	int newSocketFlag = oldSocketFlag | O_NONBLOCK;
	assert(fcntl(fd,F_SETFL,newSocketFlag) != -1);

	struct sockaddr_in addr = {
   };
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = inet_addr(ip);
	socklen_t addrlen = sizeof(addr);
	int ret = bind(fd,(const struct sockaddr*)&addr,addrlen);
	assert(ret != -1);
	ret = listen(fd,MAX_CLIENTS);
	assert(ret != -1);
	
	return fd;
}

void accept_client(int fd,int epfd){
   
	struct sockaddr_in addr = {
   };
	socklen_t len = sizeof(addr);
	int cfd = accept(fd,(struct sockaddr*)&addr,&len);
	assert(cfd != -1);
	int oldSocketflag = fcntl(cfd,F_GETFL,0);
	int newSocketFlag = oldSocketflag | O_NONBLOCK;
	assert(fcntl(fd,F_SETFL,newSocketFlag) != -1);
	struct epoll_event event ={
   };
	event.events = EPOLLIN;
	event.data.fd = cfd;
	int ret = epoll_ctl(epfd,EPOLL_CTL_ADD,cfd,&event);
	assert(ret != -1);
}

void select_fd(int fd){
   
	int epfd = epoll_create(MAX_CLIENTS);
	if(epfd == -1){
   
		perror("epoll_create");
		return;
	}
	struct epoll_event event = {
   };
	event.events = EPOLLIN;
	//event.events |= EPOLLET;
	event.data.fd = fd;
	int ret = epoll_ctl(epfd,EPOLL_CTL_ADD,fd,&event);
	if(ret == -1){
   
		perror("epoll_ctl");
		return;
	}
	while(true){
   
		struct epoll_event events[MAX_CLIENTS+1] = {
   };
		int i;

		ret = epoll_wait(epfd,events,MAX_CLIENTS+1,-1);
		if(ret == -1){
   
			perror("epoll_wait");
			break;
		}
		for(i=0;i<ret;i++){
   
			if(events[i].events & EPOLLIN){
   
				if(events[i].data.fd == fd){
   
					accept_client(fd,epfd);
				}else{
   
					char msg[1024] = {
   };
					ret = recv(events[i].data.fd,msg,1024,0);
					if(ret <= 0){
   
						ret = epoll_ctl(epfd,EPOLL_CTL_DEL,events[i].data.fd,NULL);
						assert(ret != -1);
					}else{
   
						printf("msg : %s\n",msg);
					}
				}
			}else if(events[i].events & EPOLLOUT){
   
				if(events[i].data.fd != fd)
					printf("input msg...\n");
			}
			else{
   
				//....
			}
		}
	}
}

int main(int argc,char *argv[]){
   
	if(argc < 3){
   
		printf("%s ip port\n",argv[0]);
		return -1;
	}
	int fd = init_server(argv[1],atoi(argv[2]));
	select_fd(fd);
	close(fd);
	return 0;
}

相关推荐

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-01-25 06:58:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-01-25 06:58:03       100 阅读
  3. 在Django里面运行非项目文件

    2024-01-25 06:58:03       82 阅读
  4. Python语言-面向对象

    2024-01-25 06:58:03       91 阅读

热门阅读

  1. LeetCode 93.复原IP地址 Python题解

    2024-01-25 06:58:03       62 阅读
  2. postman使用-全部总结

    2024-01-25 06:58:03       52 阅读
  3. 【Vue3】readonly 与 shallowReadonly

    2024-01-25 06:58:03       53 阅读
  4. MYSQL账号和权限配置

    2024-01-25 06:58:03       45 阅读
  5. C++中的引用

    2024-01-25 06:58:03       48 阅读
  6. 数据库(MySQL的备份和恢复)

    2024-01-25 06:58:03       47 阅读
  7. MySQL 数据加密

    2024-01-25 06:58:03       57 阅读
  8. macOS 上使用 Sublime Text 删除全部空行

    2024-01-25 06:58:03       57 阅读