简单高效epoll网络模型

来源:互联网 发布:php 取整数 编辑:程序博客网 时间:2024/06/05 20:15
#include <sys/socket.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <iostream>
#include <pthread.h>
using namespace std;
#define MAX_EVENTS 100000
pthread_mutex_t mutex;
pthread_cond_t cond1;
pthread_mutex_t mutex2;
pthread_cond_t cond2;
int listenFd;
struct task_s
{
 int fd;
 int type;//新链接  , 接收数据, 发送数据
 task_s* pNext;
 task_s* pPrepNext;
};
struct user_data {
 int fd;
 unsigned int n_size;
 char line[1024];
};

int g_epollFd;
void InitListenSocket(int epollFd, short port)
{
 listenFd = socket(AF_INET, SOCK_STREAM, 0);
 fcntl(listenFd, F_SETFL, O_NONBLOCK); // set non-blocking
 printf("server listen fd=%d\n", listenFd);
 struct epoll_event epv = { 0,{ 0 } };
 int op = EPOLL_CTL_ADD;
 epv.data.ptr = NULL;
 epv.data.fd = listenFd;
 epv.events = EPOLLIN;
 if (epoll_ctl(epollFd, op, listenFd, &epv) < 0)
  printf("Event Add failed[fd=%d],\n", listenFd);
 else
  printf("Event Add OK[fd=%d], op=%d,\n", listenFd, op);
 sockaddr_in sin;
 bzero(&sin, sizeof(sin));
 sin.sin_family = AF_INET;
 sin.sin_addr.s_addr = INADDR_ANY;
 sin.sin_port = htons(port);
 bind(listenFd, (const sockaddr*)&sin, sizeof(sin));
 listen(listenFd, 50000);
}
static int count111 = 0;
static time_t oldtime = 0, nowtime = 0;
task_s* readhead = NULL;
task_s* readtail = NULL;
task_s* accepthead = NULL;
task_s* accepttail = NULL;
void* readtask(void *args)
{
 int fd = -1;
 unsigned int n = 0;
 //用于把读出来的数据传递出去
 struct user_data *data = NULL;
 while (1)
 {
  pthread_mutex_lock(&mutex);
  //等待到任务队列不为空
  //while (readhead == NULL)
  // pthread_cond_wait(&cond1, &mutex);
  //从任务队列取出一个读任务
  
  struct task_s *tmp = readhead;
  if (readhead != NULL)
  {
   fd = readhead->fd;
   readhead = readhead->pNext;
   //printf(" accept, seq: %d \n", tmp->type);
   delete tmp;
  }
  else
  {
   pthread_mutex_unlock(&mutex);
   usleep(1000 * 100);
   continue;
  }
  pthread_mutex_unlock(&mutex);

  data = new user_data();
  data->fd = fd;
  char recvBuf[1024] = { 0 };
  int ret = 999;
  int rs = 1;
  while (rs)
  {
   ret = recv(fd, recvBuf, 1024, 0);// 接受客户端消息
   if (ret < 0)
   {
    //由于是非阻塞的模式,所以当errno为EAGAIN时,表示当前缓冲区已无数据可//读在这里就当作是该次事件已处理过。
    if (errno == EAGAIN)
    {
     printf("EAGAIN\n");
     break;
    }
    else {
     printf("recv error! fd: %d\n", fd);
     struct epoll_event epv = { 0,{ 0 } };
     epv.data.ptr = NULL;
     epoll_ctl(g_epollFd, EPOLL_CTL_DEL, fd, &epv);
     close(fd);
     rs = 0;
     break;
    }
   }
   else if (ret == 0)
   {
    // 这里表示对端的socket已正常关闭.?
    struct epoll_event epv = { 0,{ 0 } };
    epv.data.ptr = NULL;
    epoll_ctl(g_epollFd, EPOLL_CTL_DEL, fd, &epv);
    rs = 0;
    close(fd);
   }
   if (ret == sizeof(recvBuf))
    rs = 1;// 需要再次读取
   else
    rs = 0;
  }
  if (ret>0) {
   data->n_size = n;
   count111++;
   struct tm *today;
   time_t ltime;
   time(&nowtime);
   if (nowtime != oldtime) {
    printf("%d\n", count111);
    oldtime = nowtime;
    count111 = 0;
   }
   char buf[1000] = { 0 };
   sprintf(buf, "HTTP/1.0 200 OK\r\nContent-type: text/plain\r\n\r\n%s", "Hello world!\n");
   send(fd, buf, strlen(buf), 0);
   //
  }
 }
}
void * writetask(void *args);
int accepttask(void *args)
{
 struct sockaddr_in sin;
 socklen_t len = sizeof(struct sockaddr_in);
 int nfd, i;
 int events;
 // accept
  if ((nfd = accept(listenFd, (struct sockaddr*)&sin, &len)) == -1)
  {
   if (errno != EAGAIN && errno != EINTR)
   {
   }
   printf("%s: accept error!!! , %d", __func__, errno);
   usleep(1000);
   return 0;
  }
  do
  {
   // set nonblocking
   int iret = 0;
   if ((iret = fcntl(nfd, F_SETFL, O_NONBLOCK)) < 0)
   {
    printf("%s: fcntl nonblocking failed:%d", __func__, iret);
    break;
   }
   // add a read event for receive data?
   struct epoll_event epv = { 0,{ 0 } };
   int op = EPOLL_CTL_ADD;
   epv.data.ptr = NULL;
   epv.events = EPOLLIN|EPOLLET;
   epv.data.fd = nfd;
   if (epoll_ctl(g_epollFd, op, nfd, &epv) < 0)
    printf("Event Add failed[fd=%d], evnets[%d]\n", nfd, EPOLLIN);
   else
    printf("Event Add OK[fd=%d], op=%d, evnets[%0X]\n", nfd, op, EPOLLIN);
  } while (0);
  printf("-----------------new conn[%s:%d], pos[%d]---------------\n", inet_ntoa(sin.sin_addr),
   ntohs(sin.sin_port), i);
  return 0;
}
int main(int argc, char **argv)
{
 unsigned short port = 9999; // default port?
 if (argc == 2) {
  port = atoi(argv[1]);
 }
 pthread_t tid1, tid2,tid3;
 // create epoll
 g_epollFd = epoll_create(MAX_EVENTS);
 if (g_epollFd <= 0) printf("create epoll failed.%d\n", g_epollFd);
 // create & bind listen socket, and add to epoll, set non-blocking?
 InitListenSocket(g_epollFd, port);
 // event loop?
 pthread_mutex_init(&mutex, NULL);
 pthread_cond_init(&cond1, NULL);
 pthread_create(&tid1, NULL, readtask, NULL);
 pthread_create(&tid2, NULL, readtask, NULL);
 //pthread_create(&tid3, NULL, accepttask, NULL);
 //
 struct epoll_event* pEvent = new  epoll_event[MAX_EVENTS];
 printf("server running:port[%d]\n", port);

 int checkPos = 0;
 int acceptSeq = 0;
 int dataSeq = 0;
 while (1) {
  // a simple timeout check here, every time 100, better to use a mini-heap, and add timer event?
  long now = time(NULL);
  for (int i = 0; i < 100; i++, checkPos++) // doesn't check listen fd?
  {
   if (checkPos == MAX_EVENTS) checkPos = 0; // recycle
   /*
   long duration = now - g_Events[checkPos].last_active;
   if (duration >= 60 * 3)  // 60s timeout?
   {
    close(g_Events[checkPos].fd);
    printf("[fd=%d] timeout[%d--%d].\n", g_Events[checkPos].fd, g_Events[checkPos].last_active, now);
    //EventDel(g_epollFd, &g_Events[checkPos]);
    struct epoll_event epv = { 0,{ 0 } };
    epv.data.ptr = NULL;
    epoll_ctl(g_epollFd, EPOLL_CTL_DEL, fd, &epv);
   }*/
  }
  // wait for events to happen?
  int fds = epoll_wait(g_epollFd, pEvent, MAX_EVENTS, 1000);
  if (fds < 0) {
   printf("epoll_wait error, exit\n");
   break;
  }
  for (int i = 0; i < fds; i++) {
   //myevent_s *ev = (struct myevent_s*)events[i].data.ptr;
   
   if ((pEvent[i].events&EPOLLIN) && (pEvent[i].data.fd != listenFd)) // read event?
   {
    if (pEvent[i].data.fd < 0) continue;
    task_s* pt = new task_s;
    pt->fd = pEvent[i].data.fd;
    pt->type = dataSeq++;
    //printf("fds: %d  i: %d  listenFd: %d  fd: %d \n", fds, i, listenFd, events[i].data.fd);
    pt->pNext = NULL;

    pthread_mutex_lock(&mutex);
    if (readhead == NULL)
    {
     readhead = pt;
     if(readtail == NULL)
     readtail = pt;
    }
    else
    {
     readtail->pNext = pt;
     readtail = pt;
    }
    //pthread_cond_broadcast(&cond1);
    pthread_mutex_unlock(&mutex);
   }
   else if ((pEvent[i].events&EPOLLIN) && (pEvent[i].data.fd == listenFd))
   {
    
    acceptSeq++;
    printf("fds: %d  i: %d  listenFd: %d  fd: %d : acceptSeq: %d \n", fds, i, listenFd, pEvent[i].data.fd, acceptSeq);
    
    accepttask(NULL);
   
   }
   if (pEvent[i].events&EPOLLOUT) // write event?
   {
    //ev->call_back(ev->fd, events[i].events, ev->arg);
    //task_s* pt = new task_s;
    //pt->fd = events[i].data.fd;
    //pt->type = 2;
   }
  }
 }
 // free resource
 return 0;
}
0 0