单线程Rector实现回声服务器(四)

一.服务端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#include <errno.h>
#define PORT 9190
#define BUFFER_SIZE 1024
#define EPOLL_SIZE 1024

// epoll文件描述符和epoll_wait()返回事件集合
struct event_loop {
  int ep_fd;
  struct epoll_event events[EPOLL_SIZE];
};

struct event_loop *ev_loop = NULL;

// 事件
struct event_item{
  int sock_fd;                                              //  事件的文件描述符
  int (*callback)(int sock_fd, int event, void *arg);       //  事件响应回调函数
  char send_buffer[BUFFER_SIZE];                            //  事件发送缓冲区
  char receive_buffer[BUFFER_SIZE];                         //  事件接收缓冲区
  ssize_t str_len;                                          //  接收缓冲区可读长度
};

// 错误处理
void error_handler(const char *message);
// 回调函数
int accept_callback(int sock_fd, int event, void *arg);     // 坚挺套接字对应回调函数
int receive_callback(int sock_fd, int event, void *arg);    // 可接收数据套接字回调函数
int send_callback(int sock_fd, int event, void *arg);       // 可发送数据套接字回调函数

int main() {
  int server_sock;
  server_sock = socket(AF_INET, SOCK_STREAM, 0);
  if (server_sock == -1) {
    error_handler("socket() error");
  }

  struct sockaddr_in server_address;
  bzero(&server_address, sizeof(server_address));
  server_address.sin_family = AF_INET;
  server_address.sin_addr.s_addr = htonl(INADDR_ANY);
  server_address.sin_port = htons(PORT);

  if (bind(server_sock, (struct sockaddr *)&server_address, sizeof(server_address)) == -1) {
    error_handler("bind() error");
  }

  if (listen(server_sock, 5) == -1) {
    error_handler("listen() error");
  }
  
  // epoll_creat()
  ev_loop = (struct event_loop *) malloc(sizeof(struct event_loop));
  ev_loop->ep_fd = epoll_create(EPOLL_SIZE);
  
  // 监听事件初始化
  struct epoll_event event;
  event.data.fd = server_sock;
  event.events = EPOLLIN;
  struct event_item *item = (struct event_item *)malloc(sizeof(struct event_item));
  item->sock_fd = server_sock;
  item->callback = accept_callback;
  event.data.ptr = item;
  // 向epoll()注册监听套接字事件
  epoll_ctl(ev_loop->ep_fd, EPOLL_CTL_ADD, server_sock, &event);

  while (1) {
    int ep_cnt = epoll_wait(ev_loop->ep_fd, ev_loop->events, EPOLL_SIZE, -1);
    if (ep_cnt < 0) {
      break;
    }

    for (int i = 0; i < ep_cnt; i++) {
      if (ev_loop->events[i].events & EPOLLIN) {
        // 可接受数据事件(监听套接字,可recv()数据套接字)
        struct event_item *s = ev_loop->events[i].data.ptr;
        s->callback(s->sock_fd, ev_loop->events[i].events, s);
      }

      if (ev_loop->events[i].events & EPOLLOUT) {
        // 可发送数据事件
        struct event_item *s = ev_loop->events[i].data.ptr;
        s->callback(s->sock_fd, ev_loop->events[i].events, s);
      }
    }
  }
  return 0;
}

void error_handler(const char *message) {
  fputs(message, stderr);
  fputc('\n', stderr);
  exit(1);
}

int accept_callback(int sock_fd, int event, void *arg) {
  // 接收客户端连接
  int client_sock;
  struct sockaddr_in client_address;
  socklen_t client_address_size = sizeof(client_address);

  client_sock = accept(sock_fd, (struct sockaddr *)&client_address, &client_address_size);
  if (client_sock == -1) {
    return -1;
  } else {
    char str[INET_ADDRSTRLEN];
    printf("new connect from ip: %s port: %d\n", inet_ntop(AF_INET, &client_address.sin_addr.s_addr, str, INET_ADDRSTRLEN),
          ntohs(client_address.sin_port));
  }

  // 注册事件
  struct epoll_event ev;
  ev.data.fd = client_sock;
  ev.events = EPOLLIN;
  struct event_item *ev_item = (struct event_item *) malloc(sizeof(struct event_item));
  ev_item->sock_fd = client_sock;
  ev_item->callback = receive_callback;
  ev.data.ptr = ev_item;

  epoll_ctl(ev_loop->ep_fd, EPOLL_CTL_ADD, client_sock, &ev);
  return 0;
}

int receive_callback(int sock_fd, int event, void *arg) {
  struct event_item *s = (struct event_item *)arg;
  s->str_len = recv(sock_fd, s->receive_buffer, BUFFER_SIZE, 0);
  if (s->str_len < 0) {
    epoll_ctl(ev_loop->ep_fd, EPOLL_CTL_DEL, sock_fd, NULL);
    close(sock_fd);
    free(s);
    return -1;
  } else if (s->str_len == 0) {
    epoll_ctl(ev_loop->ep_fd, EPOLL_CTL_DEL, sock_fd, NULL);
    close(sock_fd);
    free(s);
    return 0;
  } else {
    // 接收到数据,将监听状态变为可写
    memcpy(s->send_buffer, s->receive_buffer, s->str_len);
    struct epoll_event ev;
    ev.events = EPOLLOUT;
    ev.data.fd = sock_fd;
    s->callback = send_callback;
    ev.data.ptr = s;
    epoll_ctl(ev_loop->ep_fd, EPOLL_CTL_MOD, sock_fd, &ev);
    bzero(s->receive_buffer, BUFFER_SIZE);
    return s->str_len;
  }
}

int send_callback(int sock_fd, int event, void *arg) {
  // 发送完成,将事件变为可读
  struct event_item *s = (struct event_item *)arg;
  send(sock_fd, s->send_buffer, s->str_len, 0);
  bzero(s->send_buffer, BUFFER_SIZE);
  struct epoll_event ev;
  ev.data.fd = sock_fd;
  ev.events = EPOLLIN;
  s->sock_fd = sock_fd;
  s->callback = receive_callback;
  ev.data.ptr = s;
  epoll_ctl(ev_loop->ep_fd, EPOLL_CTL_MOD, sock_fd, &ev);
  return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值