epollサーバプログラミング-demo


簡単なEchoServerです 
構成されたネットワーク・アドレスで傍受(0.0.0.0でも傍受)
  // create listen
  int
  init_listen_sock(int epsfd, unsigned short port)
  {
    std::vector<int> ip_list;
    if (!get_ipv4_addr(ip_list))
      return 1;

    for (int i = 0; i < ip_list.size(); i++)
      {
        int sfd = 0;
        if ((sfd = listen_on(ip_list[i], port)) < 0)
          return 1;
        int ipv4 = ip_list[i];
        unsigned char * pipv4 = (unsigned char *)&ipv4;
        LOG_INFO("listen on host: [%d.%d.%d.%d : %d]
", pipv4[0], pipv4[1], pipv4[2], pipv4[3], port ); if (ep_add(epsfd, sfd, true)) return 1; } return 0; }

epollハンドルの作成
  int ep_init()
  {
    return epoll_create(5);
  }

epollキューにソケットを追加
  int ep_add(int epfd, int sfd, bool is_listen_sock)
  {
    struct epoll_event evt;
    evt.events = EPOLLIN
                //| EPOLLOUT
                | EPOLLET
                  ;

    evt.data.ptr = malloc(sizeof(struct epoll_sock_t));
    epoll_sock_t * ptr = (epoll_sock_t *) evt.data.ptr;
    ptr->sock_fd = sfd;
    ptr->listen = is_listen_sock;

    int ret = epoll_ctl(epfd, EPOLL_CTL_ADD, sfd, &evt);
    return ret;
  }
epollキューからソケットを削除
  int ep_del(int epfd, int sfd)
  {
    int ret = epoll_ctl(epfd, EPOLL_CTL_DEL, sfd, 0);
    return ret;
  }
epollハンドルを閉じる
  int ep_shutdown(int epfd)
  {
    close(epfd);
    return 0;
  }

epollキューで待機し、読み書きイベントが発生した場合、ユーザー関数をコールバックします.
  int
  ep_wait(int epfd, ep_wait_cb_t epw_cb, void * userdata)
  {
    struct epoll_event evts[EP_MAX_WAIT_NR] = { 0 };
    for (;;)
      {
        int nfds = 0; errno = 0;
        if (0 >= (nfds = epoll_wait(epfd, evts, EP_MAX_WAIT_NR, -1)) && errno != EINTR)
          {
            break;// stop
          }
        for (int i = 0; i < nfds; i++)
          {
            epw_cb(epfd, &evts[i], userdata);
          }
      }
  }

単純な起動スレッド
void * ep_thread(void * args)
{

  int epfd = 0;
  if ((epfd = ep_init()) <= 0)
    return 0;

  unsigned short port = 8000;
  if (init_listen_sock(epfd, port))
    {
      return 0;
    }

  void * userdata = 0;
  if (ep_wait(epfd, ep_event_callback, userdata))
    {
      return 0;
    }
  if (ep_shutdown(epfd))
    {
      return 0;
    };
  return (void *)0;
}

ユーザコールバック関数
int
ep_event_callback(int epfd, struct epoll_event * evt, void * userdata)
{
  epoll_sock_t * ptr = (epoll_sock_t *) (evt->data.ptr);

  if (evt->events & EPOLLIN)
    {
      printsockinfo(ptr->sock_fd);

      if (ptr->listen) // for listen socket
        {
          sockaddr_in csa;
          socklen_t csalen = sizeof(csa);
          int clientsfd = 0;
          errno = 0;
          while ((clientsfd = accept(ptr->sock_fd, (struct sockaddr *) &csa, &csalen)) > 0)
            {
              if (setnonblocking(clientsfd))
                {
                  LOG_ERROR("fail to set client socket to non-blocking.
"); close(clientsfd); continue; } if (ep_add(epfd, clientsfd, false)) { LOG_ERROR("fail to add client socket to epoll.
"); close(clientsfd); continue; } } if (errno != EAGAIN && errno != EINTR) close(ptr->sock_fd); } else { errno = 0; char msg [0x200] = ""; while (recv(ptr->sock_fd, msg, 0x200, 0) > 0) { tm_printstamp(); LOG_INFO(" - %s \r
", msg); fflush(stdout); } if (errno != EAGAIN && errno != EINTR) { close(ptr->sock_fd); LOG_ERROR("errno=[%d]
", errno); } } } else if (evt->events & EPOLLERR) { LOG_INFO("catch an EPOLLERR, sockfd=[%d]. errno=[%d]
", ptr->sock_fd, errno); close(ptr->sock_fd); } else { LOG_INFO("epoll events [%d] Ignored, sockfd = [%d].
", evt->events, ptr->sock_fd); } return 0; }

makefileを含むプロジェクトソースファイル.
http://hi.csdn.net/attachment/201112/30/0_1325239083n82M.gif