LINUX 精通 3.1—— 2.2.1 服务器百万并发实现(实操)

2.2.1 服务器百万并发实现(实操)

实现reactor

  1. reactor核心:

    1. event与callback对应匹配
    2. 每个io与之对应的参数:读的数据存到rbuffer,rlength;写wbuffer,wlength

    不同io events对应不同的回调函数

    1. register先注册

    2. callback cb

      io ->event -> callback

      listenfd -> EPOLL_IN(当可读) ->accept_cb

      clientfd -> EPOLL_IN(当可读) ->recv_cb

      clientfd -> EPOLL_OUT(当可写) ->send_cb

      reactor不再关注io,关注event

  2. 代码实现

    在network.c 的epoll上面改

    在me下面创建我的,别搞到official官方老师的版本里去了,晚上把自己代码备份到github以防虚拟机down掉了 代码死了😿

    1. 先初始化server

      只用改sin_port

      #include<socket.h>
      #include<netinet/in.h>
      #include<string.h>
      #include<errno.h>
      
      int init_server(unsigned short port){
          // 创建抄network里
          // 创建socket
          int sockfd = socket(AF_INET, SOCK_STREAM, 0);
          
          // 绑定本地端口
          struct sockaddr_in servaddr;
          servaddr.sin_family = AF_INET; 
          servaddr.sin_addr.s_addr = htons(INADDR_ANY); //绑网卡地址 默认0.0.0.0 绑本地地址;htons转成网络字节序 
          servaddr.sin_port = htons(port); //改这里 0-1023系统默认 大于1024都能用
      
          if(-1 == bind(sockfd, (struct sockaddr*)&servaddr, sizeof(struct sockaddr))){
              printf("bind failed: %s\n", strerror(errno));
          }
          
          listen(sockfd, 10);
          printf("listen finished: %d\n", sockfd);
      
          return sockfd;
      }
      
      
    2. set event

      改事件的地方,还是用到了epoll没全用

      #include<epoll.h>
      
      // global variable
      // 抄epoll里构建事件, 把io加入epoll里 不一样封装到set_event里
      // int epfd = epoll_create(1); //不可以这样写,在里面改值
      int epfd = 0;
      
      
      
      int set_event(int fd, int event){
          
          struct epoll_event ev; //构建事件,只用来add和delete,control里没用
          ev.events = event;  //改这里不用epoll,reactor用event
          ev.data.fd = fd;
          epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev); 
      
      }
      
      int main(){
          unsigned short port = 2000;
          int sockfd = init_server(port);
      
          epfd = epoll_create(1);
          set_event(sockfd, EPOLLIN);
      
      }
      
    3. 构建事件对应的回调函数callback

      比如EPOLL_IN 要么accept要么recv callback

      #define BUFFER_LENGTH 1024
      typedef int (*RCALLBACK)(int fd); //用于定义一个函数指针类型RCALLBACK。它表示一个接受一个int类型参数fd并返回int类型的函数指针
      
      struct conn{
          int fd; //io是fd
      
          char rbuffer[BUFFER_LENGTH];
          int rlength;
          char wbuffer[BUFFER_LENGTH];
          int wlength;
      
          RCALLBACK send_callback;
         
          // epollin事件对应callback要么accept或者recv
          /*
          这段代码定义了一个联合体(union)r_action,它包含两个成员:accept_callback和recv_callback,它们都是RCALLBACK类型的函数指针。
          在使用union时,各成员共享同一块内存空间,只能同时使用其中的一个成员。不同成员可以存储不同类型的数据,但在任意给定时间点上只能使用一个成员。
          该联合体的目的可能是为了提供某种灵活性,在特定情况下可以选择调用accept_callback或recv_callback函数来处理相应的操作。
          */
          union{
              RCALLBACK accept_callback;
              RCALLBACK recv_callback;
          }r_action;
      }
      
      
    4. accept recv send回调函数

      // listenfd(sockfd) --> EPOLLIN --> accept_cb
      int accept_cb(int fd) {
      
      	struct sockaddr_in  clientaddr;
      	socklen_t len = sizeof(clientaddr);
      
      	int clientfd = accept(fd, (struct sockaddr*)&clientaddr, &len);
      	printf("accept finshed: %d\n", clientfd);
      
          conn_list[clientfd].fd = clientfd;
          conn_list[clientfd].r_action.recv_callback = recv_cb;
          conn_list[clientfd].send_callback = send_cb;
      
          memset(conn_list[clientfd].rbuffer, 0, BUFFER_LENGTH);
          conn_list[clientfd].rlength = 0;
      
          memset(conn_list[clientfd].wbuffer, 0, BUFFER_LENGTH);
          conn_list[clientfd].wlength = 0;
          
          set_event(clientfd, EPOLLIN);
      	return 0;
      }
      
      
      int recv_cb(int fd) {
          
          int count = recv(fd, conn_list[fd].rbuffer, BUFFER_LENGTH, 0);
      	if (count == 0) { // disconnect
      		printf("client disconnect: %d\n", fd);
      		close(fd);
      
      		epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL); // unfinished
      
      		return 0;
      	} 
          printf("RECV: %s\n", conn_list[fd].rbuffer);
          set_event(fd, EPOLLOUT);
      
          return count;
      }
      
      int send_cb(int fd) {
          
          int count = send(fd, conn_list[fd].wbuffer, count, 0);
      
          set_event(fd, EPOLLIN);
      
          return count;
      }
      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值