高并发epoll,TCP服务端


前言

所有的服务器都是高并发的,可以同时为成千上万个客户端提供服务,这一技术又被称为IO复用。


提示:以下是本篇文章正文内容,下面案例可供参考

一、epoll是什么?

IO复用的基本思想是事件驱动,服务器同时保持多个客户端IO连接,当这个IO上有可读或可写事件发生时,表示这个IO对应的客户端在请求服务器的某项服务,此时服务器响应该服务。在Linux系统中,IO复用使用select, poll和epoll来实现。epoll改进了前两者,更加高效、性能更好,是目前几乎所有高并发服务器的基石。
epoll介绍和原理

二、代码详情

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <iostream>
#include<sys/select.h>
#include<sys/epoll.h>
#include <fcntl.h>
#include <errno.h>
using namespace std;

#define MAX_EVENTS 1024
#define READ_BUFFER 1024

int setnonblocking(int fd)
{
  fcntl(fd,F_SETFL,fcntl(fd,F_GETFL) | O_NONBLOCK);
}

int main()
{

int sockfd;//服务器端套接字
sockfd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);//创建服务器端套接字

sockaddr_in serveraddr = {};服务器网络地址结构体
serveraddr.sin_family = AF_INET;//设置为IP通信
serveraddr.sin_port =htons(1234);//服务器端口号
serveraddr.sin_addr.s_addr = INADDR_ANY;//服务器IP地址
//serveraddr.sin_addr.s_addr = inet_addr("127.0.0.1");//服务器IP地址

 /*将套接字绑定到服务器的网络地址上*/
bind(sockfd,(sockaddr*)&serveraddr,sizeof(serveraddr));

 /*监听连接请求*/
listen(sockfd,SOMAXCONN);

socklen_t  clnt_addr_len = sizeof(serveraddr);
int epfd = epoll_create1(0);//创建一个epoll对象epfd
  struct epoll_event events[MAX_EVENTS], ev;
  bzero(&events,sizeof(events));
  bzero(&ev,sizeof(ev));

  ev.events = EPOLLIN;    //在代码中使用了ET模式,且未处理错误,在day12进行了修复,实际上接受连接最好不要用ET模式
  ev.data.fd = sockfd;    //该IO口为服务器socket fd
  
  epoll_ctl(epfd,EPOLL_CTL_ADD, sockfd, &ev);    //将服务器socket fd添加到epoll

  while(true){    // 不断监听epoll上的事件并处理
    int nfds = epoll_wait(epfd, events, MAX_EVENTS, -1);   //有nfds个fd发生事件
    for(int i = 0; i < nfds; ++i){  //处理这nfds个事件
        if(events[i].data.fd == sockfd){    //发生事件的fd是服务器socket fd,表示有新客户端连接
          struct sockaddr_in clientaddr;
          bzero(&clientaddr,sizeof(clientaddr));
          socklen_t naddrlen;
          naddrlen = sizeof(clientaddr);
          int clnt_sockfd = accept(sockfd, (sockaddr*)&clientaddr, &naddrlen);
          bzero(&ev,sizeof(ev));
          
          ev.data.fd = clnt_sockfd;   
          ev.events = EPOLLIN | EPOLLET;  //对于客户端连接,使用ET模式,可以让epoll更加高效,支持更多并发
          setnonblocking(clnt_sockfd);    //ET需要搭配非阻塞式socket使用
          epoll_ctl(epfd, EPOLL_CTL_ADD, clnt_sockfd, &ev);   //将该客户端的socket fd添加到epoll

        } else if(events[i].events & EPOLLIN){      //发生事件的是客户端,并且是可读事件(EPOLLIN)
           char buf[READ_BUFFER];
           while (1)
           {
             memset(buf,0,READ_BUFFER);
             ssize_t byte_red = read(events[i].data.fd,buf,sizeof(buf));
             if (byte_red > 0)
             {
               printf("message client fd %d:%s\n",events[i].data.fd,buf);
               write(events[i].data.fd,buf,sizeof(buf));
             }
             else if (byte_red == -1 && errno == EINTR) //正常中断
             {
               printf("continue \n");
               continue;
             }
             else if (byte_red == -1 && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))//非阻塞io,条件表示数据全部读取完毕
             {
               break;
             }
             else if (byte_red == 0)//断开连接
             {
               printf("disconnected  client fd %d\n",events[i].data.fd);
               close(events[i].data.fd);
               break;
             }
           }
        }
    }
}
close(sockfd);
return 0;
}

总结

使用epoll实现高并发的TCP服务器。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值