服务器比较简陋,为了学习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 }  

转载于:https://www.cnblogs.com/jiangzhaowei/p/8831108.html

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

  1. Linux网络编程——基于tcp/ip的模拟聊天(文件传输)工具

    开发平台:Linux 开发工具:Ubuntu, sourceInsight4.0 项目介绍: 本项目基于TCP/IP协议创建一个网络通信系统,可以实现客户之间的聊天通信以及文件传输,同时利用进程实现多 ...

  2. 网络编程——基于TCP协议的通讯录【课程设计】

    网络编程--基于TCP协议的通讯录[课程设计] 本文目录 网络编程--基于TCP协议的通讯录[课程设计] 一.设计题目和要求 设计目标: 课程设计系统组成及模块功能: 二.设计内容 服务端 客户端 S ...

  3. 【Linux网络编程】TCP带外数据

    [Linux网络编程]TCP带外数据 [1]TCP 包的部首 TCP带外数据相关概念 紧急字段URG     : 当URG=1时,告诉系统此报文段中有紧急数据,应尽快传送. 紧急指针         ...

  4. 【Linux网络编程】TCP编程

    00. 目录 文章目录 00. 目录 01. TCP概述 02. TCP特点 03. TCP中CS架构 04. TCP相关函数 05. TCP服务端示例 06. TCP客户端示例 07. 附录 01. ...

  5. 【Linux网络编程】TCP三次握手和四次挥手

    00. 目录 文章目录 00. 目录 01. 三次握手 02. 四次挥手 03. 三次握手和四次挥手原因 04. 2MSL 05. 附录 01. 三次握手 在 TCP/IP 协议中,TCP 协议提供可 ...

  6. 【Linux网络编程】TCP网络编程中connect listen和accept三者之间的关系

    00. 目录 文章目录 00. 目录 01. TCP服务端和客户端流程 02. connect函数 03. listen函数 04. 三次握手 05. accept函数 06. 附录 01. TCP服 ...

  7. 【Linux网络编程】TCP网络编程中connect()、listen()和accept()三者之间的关系

    基于 TCP 的网络编程开发分为服务器端和客户端两部分,常见的核心步骤和流程如下: connect()函数 对于客户端的 connect() 函数,该函数的功能为客户端主动连接服务器,建立连接是通过三 ...

  8. 【Linux网络编程】TCP

    概述 TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的.可靠的.基于字节流的传输层通信协议. TCP 具有以下特点: 1)电话系统服务模式的抽象 2) ...

  9. Linux网络编程 - 基于UDP的服务器端/客户端

    一 理解UDP 1.0 UDP协议简介 UDP(User Datagram Protocol,用户数据报协议) [RFC 768] UDP协议的数据传输单元叫 UDP用户数据报,而TCP协议的数据传输 ...

最新文章

  1. 【转】c++虚函数实现原理
  2. redis实现购物车
  3. kvm直通sata_基于KVM的SRIOV直通配置及性能测试
  4. jquery完成界面无刷新加载登陆注册
  5. javascript初学者_针对JavaScript初学者的调试技巧和窍门
  6. c和java内存泄漏区别_内存溢出和内存泄漏的区别(转)
  7. java获取指定年月往前推12个月的年月_java 获取日期的几天前,几个月前和几年前的实例...
  8. Hello can not find git path
  9. 运筹说 第36期 | 算法介绍之运输问题
  10. Ubuntu安装配置tftp服务器
  11. nodejs 之创建文件
  12. 难说 | 新读了几本书
  13. win10 声音设置
  14. 安卓手机版微信聊天加密软件 悬浮窗版本
  15. 阿里云国际站-阿里云在其云峰会上推出新的直播电子商务解决方案
  16. 一文了解数据分析师视角下的数据中台
  17. 老婆离家三周,我写了一个操作系统!
  18. ps中海报设计的设计思路
  19. ACM论文字体及透明度的问题
  20. NTP校时系统(网络校时服务器)让交通系统更加智慧

热门文章

  1. SSH暴力破解IP大曝光
  2. Linux shell 正则表达式用法
  3. AI部署前路坎坷,50%项目半路夭折
  4. java 图形用什么组件标题_java图形用户界面设计Swing常用组件(阅读).ppt
  5. xshell远程连接自动断开的问题解决
  6. 031_MessageBox弹框
  7. 012_Spring Data Redis
  8. 002_SpringIOC
  9. 实验6Linux系统开发环境,哈工大嵌入式操作系统课件—6 Linux开发环境1-linux基.ppt...
  10. java enum判断_Java Enum枚举 遍历判断 四种方式(包括 Lambda 表达式过滤)