zoukankan      html  css  js  c++  java
  • 基于EPOLL写的HTTP服务器(加入了线程池)_没落都城_新浪博客

    基于EPOLL写的HTTP服务器(加入了线程池)_没落都城_新浪博客

        基于EPOLL写的HTTP服务器(加入了线程池)
        (2010-12-07 19:02:51)
        转载▼
        标签:
        杂谈
            分类: EPOLL
        #include<fcntl.h>
        #include<cstdio>
        #include<unistd.h>
        #include<cstdlib>
        #include<sys/socket.h>
        #include<sys/epoll.h>
        #include<netinet/in.h>
        #include<arpa/inet.h>
        #include<errno.h>
        #include<cstring>
        #include<pthread.h>
        const int EPOLL_SIZE=5000;
        const int EVENT_ARR=5000;
        const int PORT=8002;
        const int BUF_SIZE=5000;
        const int BACK_QUEUE=100;
        const int THREAD_MAX=100;
        static unsigned int s_thread_para[THREAD_MAX][8];   //线程参数
        static pthread_t s_tid[THREAD_MAX];                 //线程ID
        pthread_mutex_t s_mutex[THREAD_MAX]; //线程锁
        int epFd;                            //epoll
        struct epoll_event ev,evs[EVENT_ARR];
        char *get_type(char *url,char *buf)
        {
           const char *t=url+strlen(url);
           char type[64];
           for(;t>=url&&*t!='.';--t)  ;
           strcpy(type,t+1);
           if(strcmp(type,"html")==0||strcmp(type,"htm")==0)
                   sprintf(buf,"text/%s",type);
           else if(strcmp(type,"gif")==0||
                 strcmp(type,"jpg")==0||
                 strcmp(type,"jpeg")==0||
                 strcmp(type,"png")==0)
                 sprintf(buf,"image/%s",type);
          else if(strcmp(type,"/")==0)
              sprintf(buf,"text/html");
          else if(strcmp(type,"css")==0)
                sprintf(buf,"text/css");
          else if(strcmp(type,"js")==0)
             sprintf(buf,"application/x-javascript");
          else
              {
            
              sprintf( buf, "unknown" );
              }
              return buf;
        }
         void* http_server(int thread_para[])
        {
              int pool_index;           //thread pool ID
              int clientFd;             //client socket
              char buf[BUF_SIZE];
              pthread_detach(pthread_self());
              pool_index=thread_para[7];
         wait_unlock:
                 pthread_mutex_lock(s_mutex+pool_index); //wait for thread unlock
                 clientFd=thread_para[1];                //client socket ID
                                      //先进行试探性读取
                   int len=read(clientFd,buf,BUF_SIZE);
                      printf("%s",buf);
                      if(len>0)
                                   {
                     char *token=strtok(buf," ");          //GET
                   printf("token:%s",token);
                     char type[64];
                   char *url=strtok(NULL," ");           //URL
                   while(*url=='.'||*url=='/')++url;
                   printf("url:%s",url);
                   char file[1280000];
                   sprintf(file,"%s",url);
                   printf("file:%s",file);
                     FILE *fp=fopen(file,"rb");
                     if(fp==0)
                        {
                        char response[]="HTTP/1.1 404 NOT FOUND\r\n\r\n";
                        printf("HTTP/1.1 404 NOT FOUND\r\n\r\n");
                        write(clientFd,response,strlen(response));
                        }
                     else
                     {
                    int file_size;
                    char *content;
                    char *response;
                    fseek(fp,0,SEEK_END);
                    file_size=ftell(fp);
                    fseek(fp,0,SEEK_SET);
                    content=(char *)malloc(file_size+1);
                    response=(char*)malloc(200);
                    fread(content,file_size,1,fp);
                      content[file_size]=0;
                      sprintf(response,"HTTP/1.1 200 OK\r\nContent-Length:%d\r\nContent-Type:%s\r\n\r\n",file_size,get_type(url,type));
                     // printf("HTTP/1.1 200 OK\r\nContent-Type:%s\r\nContent-Length:%d\r\n\r\n%s",get_type(url,type),file_size,content);
                      write(clientFd,response,strlen(response));
                      write(clientFd,content,file_size);
                      free(content);
                      free(response);
                                      }
                                   }
                      else if(len==0)
                                                       {
                                                         //触发了EPOLL事件,却没有读取,表示断线
                           //printf("Client closed at %s\n",inet_ntoa(clientAddr.sin_addr));
                           epoll_ctl(epFd,EPOLL_CTL_DEL,clientFd,&ev);
                           close(clientFd);
                           int i=thread_para[3];
                           evs[i].data.fd=-1;
                                                       }
                       else if(len==EAGAIN)
                                                    {
                         printf("socket huan cun man le!\n");
                                                    }
                       else
                                                    {
                          //client读取出错
                          printf("Client read failed!\n");
                                                    }
               thread_para[0] = 0;//设置线程占用标志为"空闲"
               goto wait_unlock;
               printf("pthread exit!\n");
               pthread_exit(NULL);
        }
        static int init_thread_pool(void)
        {
            int i,rc;
            for(i=0;i<THREAD_MAX;i++)
            {
             s_thread_para[i][0]=0;  //idle
             s_thread_para[i][7]=i;   //thread pool ID
             pthread_mutex_lock(s_mutex+i);   //thread lock
            }
            // create thread pool
            for(i=0;i<THREAD_MAX;i++)
            {  rc=pthread_create(s_tid+i,0,(void *(*)(void*))&http_server,(void *)(s_thread_para[i]));
               if(0!=rc)
                { fprintf(stderr,"Create thread failed!\n");
                   return -1;
                            }
                   }
            return 0;
        }
        void setnoblock(int sockFd)         //设置非阻塞模式
        {
        int opt;
        if((opt=fcntl(sockFd,F_GETFL))<0)  //获取原来的flag;
            {
            printf("GET FL failed!\n");
            exit(-1);
             }
         opt|=O_NONBLOCK;
          if(fcntl(sockFd,F_SETFL,opt)<0)
         printf("SET FL failed!\n");
        }
        int main()
        {
          int serverFd,j;
          serverFd=socket(AF_INET,SOCK_STREAM,0); //创建服务器fd
            setnoblock(serverFd);                   //设置为非阻塞模式
            unsigned int        optval;
            struct linger        optval1;
            //设置SO_REUSEADDR选项(服务器快速重起)
              optval = 0x1;
              setsockopt(serverFd, SOL_SOCKET, SO_REUSEADDR, &optval, 4);
             // 设置SO_LINGER选项(防范CLOSE_WAIT挂住所有套接字)
             optval1.l_onoff = 1;
             optval1.l_linger = 60;
             setsockopt(serverFd, SOL_SOCKET, SO_LINGER, &optval1, sizeof(struct linger));
                  //创建epoll,并将serverFd放入监听队列
            epFd=epoll_create(EPOLL_SIZE);
            ev.data.fd=serverFd;
            ev.events=EPOLLIN|EPOLLET;
            epoll_ctl(epFd,EPOLL_CTL_ADD,serverFd,&ev);
                 //绑定服务器端口
           struct sockaddr_in serverAddr;
           socklen_t serverlen=sizeof(struct sockaddr_in);
           serverAddr.sin_addr.s_addr=htonl(INADDR_ANY);
           serverAddr.sin_port=htons(PORT);
            if(bind(serverFd,(struct sockaddr*)&serverAddr,serverlen))
                  {
               printf("BIND failed!\n");
               exit(-1);
                  }
            //线程池初始化
            int rc = init_thread_pool();
            if (0 != rc) exit(-1);
            //打开监听
            if(listen(serverFd,BACK_QUEUE))
                  {
                  printf("Listen failed!\n");
                  exit(-1);
                  }
                //服务处理
            int clientFd;
            sockaddr_in clientAddr;
            socklen_t clientlen;
            for(;;)
                {
             //等待epoll事件到来,最多取EVENT_ARR个事件
             int nfds=epoll_wait(epFd,evs,EVENT_ARR,-1);
             //处理事件
             for(int i=0;i<nfds;i++)
              {
              if(evs[i].data.fd==serverFd&&evs[i].events&EPOLLIN)
                    {
                      //如果是serverFd,表明有新连接连入
                  if((clientFd=accept(serverFd,(struct sockaddr*)&clientAddr,&clientlen))<0)
                                       {
                     printf("ACCEPT  failed\n");
                                       }
                  printf("Connect from %s:%d\n",inet_ntoa(clientAddr.sin_addr),htons(clientAddr.sin_port));
                setnoblock(clientFd);
                          //注册accept()到的连接
                ev.data.fd=clientFd;
                ev.events=EPOLLIN|EPOLLET;
                epoll_ctl(epFd,EPOLL_CTL_ADD,clientFd,&ev);
                    }
              else if(evs[i].events&EPOLLIN)
              {
                          //如果不是serverFd,则是client的可读
              printf("client can write!\n");
              if((clientFd=evs[i].data.fd)>0)
                   {
                     //查询空闲线程对
                  for(j = 0; j < THREAD_MAX; j++) {
                      if (0 == s_thread_para[j][0]) break;
                  }
                  if (j >= THREAD_MAX) {
                      fprintf(stderr, "线程池已满, 连接将被放弃\r\n");
                      shutdown(clientFd, SHUT_RDWR);
                      close(clientFd);
                      continue;
                  }
                  //复制有关参数
                  s_thread_para[j][0] = 1;//设置活动标志为"活动"
                  s_thread_para[j][1] = clientFd;//客户端连接
                  s_thread_para[j][2] = serverFd;//服务索引
                  s_thread_para[j][3]=i;             //epoll event id;
                  //线程解锁
                  pthread_mutex_unlock(s_mutex + j);  }
              else printf("other error!\n");
              }
                 }
                }
            return 0;
        }
  • 相关阅读:
    【Ebola】python day4
    源代码管理SVN的使用
    源代码管理git的使用
    UIViewController的生命周期及iOS程序执行顺序
    iOS
    Quartz2D知识点聚合案例
    iOS之NSAttributedString-------字符属性
    iOS-控件响应用户控制事件之事件处理
    UINavigationController
    程序启动的完整过程
  • 原文地址:https://www.cnblogs.com/lexus/p/2988829.html
Copyright © 2011-2022 走看看