zoukankan      html  css  js  c++  java
  • 【Linux网络编程】基于TCP流 I/O多路转接(poll) 的高性能http服务器

    服务器比较简陋,为了学习poll的使用,只向客户端回写一条html语句。启动服务器后,浏览器发起请求,服务端向浏览器写回html,响应字符串,然后可以看到,浏览器解析并显示 Hello Poll!.

    启动服务端:

    用浏览器访问:

    浏览器解析出字符串:

    完整代码:

      1 #include <stdio.h>  
      2 #include <stdlib.h>  
      3 #include <unistd.h>  
      4 #include <netinet/in.h>  
      5 #include <arpa/inet.h>  
      6 #include <unistd.h>  
      7 #include <string.h>   
      8 #include <poll.h>  
      9 #include <sys/socket.h>  
     10 #include <sys/types.h>  
     11 #include <sys/stat.h>  
     12   
     13   
     14 #define POLLFD_SIZE 1024 /* struct pollfd 结构体数组最大上限 */  
     15   
     16   
     17   
     18 /* 关心描述符集事件数组*/  
     19 struct pollfd array_pollfd[POLLFD_SIZE];  
     20   
     21 /* 结构体成员详情 
     22 struct pollfd  
     23 { 
     24     int fd;        // 关心的描述符 
     25     short events;  // 关心的事件 
     26     short revents; // 发生的事件 
     27 }; 
     28 */  
     29   
     30 /* 获取一个监听连接的sockfd */  
     31 int run_getsockfd(const char*ip, int port);  
     32   
     33 /* 执行poll检测 */  
     34 void run_poll(int listen_sockfd);  
     35   
     36 /* 响应客户端的连接,并添加新的描述符到关心事件中 */  
     37 void run_accept(int listen_sock);  
     38   
     39 /* 当与客户端连接的描述符有事件就绪时,做出响应 */  
     40 void run_action( int index);  
     41   
     42 int main(int argc, char **argv)  
     43 {  
     44     if(argc != 3)  
     45     {  
     46         printf("usage: [server_ip] [server_port]");  
     47         return 1;  
     48     }  
     49   
     50     int listen_sockfd = run_getsockfd(argv[1], atoi(argv[2]));  
     51   
     52     run_poll(listen_sockfd);  
     53   
     54     return 0;  
     55 }  
     56   
     57   
     58 /* 调用poll 并检测返回事件 */  
     59 void run_poll(int listen_sockfd)  
     60 {  
     61     /* 将负责监听连接的sockfd注册事件 */  
     62     array_pollfd[0].fd = listen_sockfd;  
     63     array_pollfd[0].events = POLLIN;  
     64   
     65     /* 初始化数组中的描述符 */  
     66     int idx_init = 1;  
     67     for(; idx_init < POLLFD_SIZE; ++idx_init)  
     68     {  
     69         array_pollfd[idx_init].fd = -1;  
     70     }  
     71     int timeout = 1000; /* 设定一秒后超时 */  
     72   
     73   
     74     while(1)  
     75     {  
     76         int ret_poll = poll(array_pollfd,  POLLFD_SIZE, timeout);  
     77   
     78         if(ret_poll == 0)        /* 超时    */  
     79             printf("timeout
    ");  
     80         else if(ret_poll < 0)    /* 执行出错*/  
     81             perror("poll()");  
     82         else  
     83         {/* 有关心的事件就绪  */  
     84   
     85             /* 遍历数组,轮询检测poll的结果  */  
     86             int idx_check = 0;  
     87             for(idx_check = 0; idx_check < POLLFD_SIZE; ++idx_check)  
     88             {  
     89                 if(idx_check == 0 && array_pollfd[0].revents & POLLIN)  
     90                 {/* listen_sockfd 读事件就绪 */  
     91                     run_accept(listen_sockfd);   
     92                 }  
     93                 else if(idx_check != 0)  
     94                 {/* 与客户端连接的sockfd 有事件就绪 */  
     95                     run_action(idx_check);  
     96                 }  
     97             }  
     98         }  
     99     } // end while 1  
    100 }  
    101   
    102   
    103 /* 当与客户端连接的描述符有事件就绪时,做出响应 */  
    104 void run_action( int index)  
    105 {  
    106     if(array_pollfd[index].revents & POLLIN)  
    107     {/* 客户端读事件发生 */  
    108         char buf[1024];          /* 存储从客户端读来的消息 */   
    109         memset(buf, 0, sizeof(buf));  
    110         ssize_t s = read(array_pollfd[index].fd, buf, sizeof(buf)-1);  
    111         if(s > 0)  
    112         {  
    113             buf[s-1] = '';  
    114             printf("client say$ %s 
    ", buf);  
    115             array_pollfd[index].events = POLLOUT;  
    116         }  
    117         else if( s <= 0)  
    118         {  
    119             printf("client quit!
    ");  
    120             close(array_pollfd[index].fd);  
    121             array_pollfd[index].fd = -1;  
    122         }  
    123   
    124     }  
    125     else if (array_pollfd[index].revents & POLLOUT)  
    126     {/* 客户端写事件发生 */  
    127         /* 使用浏览器测试,写回到客户端,浏览器会解析字符串,显示 Hellp Epoll! */  
    128         const char* msg = "HTTP/1.1 200 OK
    
    <html><br/><h1>Hello poll!</h1></html>";  
    129         write(array_pollfd[index].fd, msg, strlen(msg));      
    130         close(array_pollfd[index].fd);  
    131         array_pollfd[index].fd = -1;  
    132     }  
    133 }  
    134   
    135   
    136 /* 响应客户端的连接,并添加新的描述符到关心事件中 */  
    137 void run_accept(int listen_sock)  
    138 {  
    139     struct sockaddr_in cliaddr;  
    140     socklen_t clilen = sizeof(cliaddr);  
    141   
    142     int new_sock = accept(listen_sock, (struct sockaddr*)&cliaddr, &clilen);  
    143     if( new_sock < 0)  
    144     {  
    145         perror("accept");  
    146         return ;  
    147     }  
    148   
    149     printf("与客户端连接成功: ip %s port %d 
    ", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port));  
    150     /* 将新socket描述符添加到数组中 */  
    151     int idx_find = 1;  
    152     for(; idx_find < POLLFD_SIZE; ++idx_find)  
    153     {  
    154         if(array_pollfd[idx_find].fd < 0)  
    155         {  
    156             array_pollfd[idx_find].fd = new_sock;  
    157             array_pollfd[idx_find].events = POLLIN ;  
    158             break;  
    159         }  
    160     }     
    161     if(idx_find == POLLFD_SIZE)  
    162     {  
    163         perror("连接超出最大限度,add array_pollfd[]");  
    164         return;  
    165     }  
    166   
    167 }  
    168   
    169 /* 获取一个监听socket */  
    170 int run_getsockfd(const char* ip, int port)  
    171 {  
    172     int sock = socket(AF_INET, SOCK_STREAM, 0);  
    173     if( sock < 0){  
    174         perror("socket()");  
    175         exit(1);  
    176     }  
    177   
    178     int opt = 1;  
    179     setsockopt(sock , SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));  
    180   
    181     struct sockaddr_in server;  
    182     bzero(&server, sizeof(server));  
    183     server.sin_addr.s_addr = inet_addr(ip);  
    184     server.sin_port = htons(port);  
    185     server.sin_family = AF_INET;  
    186   
    187     if(bind(sock, (struct sockaddr *)&server, sizeof(server) ) < 0){  
    188         perror("bind()");  
    189         exit(2);  
    190     }  
    191   
    192     if(listen(sock, 5) < 0){  
    193         perror("listen()");  
    194         exit(3);  
    195     }  
    196   
    197     return sock;  
    198 }  
  • 相关阅读:
    Backbone Events 源码笔记
    IIS8集成模式下打开静态资源被aspx处理程序处理,StaticFileModule失效问题分析
    Orchard 与 ABP架构比较 (aspnetboilerplate)
    Orchard EventBus 事件总线及 IEventHandler作用
    Orchard 事件通知小坑
    推荐一个国内编程语言排名网站
    po_文件格式[转]
    关于poedit打开po文件乱码的问题
    JAVA和.NET工作流相关项目收集
    php里的二进制安全
  • 原文地址:https://www.cnblogs.com/jiangzhaowei/p/8831108.html
Copyright © 2011-2022 走看看