epoll的边沿触发的多线程

服务器的并发本质上都一样,都是将创建连接、收发数据的功能分配给子线程;父线程仅负责while循环下进行检测

父进程

1、完成服务器的设置;
2、创建epoll树和监听的epoll实例;
3、完成while循环,并把参数传递给子进程。

int main()
{
	//完成线程锁的初始化
	pthread_mutex_init(&mutex,NULL);

    // 创建监听的lfd
    int lfd = socket(AF_INET, SOCK_STREAM, 0);

    // 定义服务器性质,并储存在sockaddr_in addr中;绑定。
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(9999);
    addr.sin_addr.s_addr = INADDR_ANY;
    bind(lfd, (struct sockaddr*)&addr, sizeof(addr));
	
	//开启监听
	listen(lfd, 128);

	//创建epoll树
	int epfd = epoll_create(100);

	//上锁
	pthread_mutex_lock(&mutex);
	
	//创建epoll实例以及实例的数组
	struct epoll_event ev;
	ev.events = EPOLLIN;  
	ev.data.fd = lfd;
	int ret = epoll_ctl(epfd, EPOLL_CTL_ADD, lfd, &ev);
	
	struct epoll_event evs[1024];
	int size = sizeof(evs) / sizeof(struct epoll_event);

	//开始循环
	while(1)
	{
	int num = epoll_wait(epfd, evs, size, -1);
	for(int i = 0; i < num; i++)
	{
		int curfd = evs[i].data.fd;
		if(curfd == lfd)
		{
			Info info;
			info.lfd = lfd;
			info.epfd = epfd;
			info.ev.events = EPOLLIN | EPOLLET;  
			info.ev.data.fd = curfd;
			
			pthread_t tid;
			pthread_create(&tid,NULL,acceptConn,&info);
			pthread_detach(tid);
		}
		else 
		{
			Info info;
			info.lfd = lfd;
			info.epfd = epfd;
			info.ev.events = EPOLLIN | EPOLLET;  
			info.ev.data.fd = curfd;
			
			pthread_t tid;
			pthread_create(&tid,NULL,Communication,&info);
			pthread_detach(tid);
		}
	}
}
	

子进程

监听子进程

typedef struct Info{
	int epfd; 
	int lfd;
	struct epoll_event ev;
}

---------------------------------------------------------------------------------------------
void* acceptConn(void *arg)
{
	Info* tmp = (Info*) arg;
	int fd = tmp->ev.data.fd;//取出监听的fd
	
	int cfd = accept(fd , NULL, NULL);

	tmp.ev.events = EPOLLIN | EPOLLET;  
	tmp.ev.data.fd = cfd;

	//获得flag信息并修改
	int flag = fcntl(cfd, F_GETFL);
	flag |= O_NONBLOCK;                                                        
	fcntl(cfd, F_SETFL, flag);

	pthread_mutex_lock(&mutex);
	int ret = epoll_ctl(tmp->epfd, EPOLL_CTL_ADD, cfd, &(tmp->ev));//该ev已经在外面写好了,并且随着info传进来了,可以直接使用
	pthread_mutex_unlock(&mutex);

	
}

读写子线程

void Communication(void *argv){
   // 处理通信的文件描述符
   // 接收数据
 			    int* info = (int*) argv;
                char buf[1024];
                memset(buf, 0, sizeof(buf));
                while(1)
                {
                int len = recv((info ->ev).data.fd, buf, sizeof(buf), 0);
                if(len == -1)
				{
					if(errno = EAGAIN) //头文件error.h
					{
						printf("数据读取完毕");
						send(info->lfd,buf,strlen(buf)+1,0);
                        epoll_ctl(info->epfd, EPOLL_CTL_DEL,(info>ev).data.fd, NULL);
                        close((info ->ev).data.fd);
                        break;
					}
					else
					{
						perror("recv error");
						break;
						//如果使用exit会退出全部线程
					}
				}
				}
}

注意:当打印buff里面的字符串时,如果结尾处没有"/0"容易导致末尾处的一个字节的乱码。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值