分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > IT知识

【Linux网络编程】基于TCP流 I/O多路转接(poll) 的高性能http服务器

发布时间:2023-09-06 01:49责任编辑:沈小雨关键词:httpLinux

服务器比较简陋,为了学习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\n"); ??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] = ‘\0‘; ?114 ????????????printf("client say$ %s \n", buf); ?115 ????????????array_pollfd[index].events = POLLOUT; ?116 ????????} ?117 ????????else if( s <= 0) ?118 ????????{ ?119 ????????????printf("client quit!\n"); ?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\r\n\r\n<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 \n", 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 } ?

【Linux网络编程】基于TCP流 I/O多路转接(poll) 的高性能http服务器

原文地址:https://www.cnblogs.com/jiangzhaowei/p/8831108.html

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved