不为客户连接创建子进程的并发回射服务器( poll实现 )
前言
在上文中,我使用select函数实现了不为客户连接创建子进程的并发回射服务器( 点此进入 )。但其中有个细节确实有点麻烦,那就是还得设置一个client数组用来标记select监听描述符集中被设置为监听位的位。有没有方法简化这个处理呢?有!在《UNIX网络编程》第六章最后介绍了一种类似select的函数 --- poll函数,用它来实现IO复用使代码简化了不少( 起码并发回射服务器的例子是的 )。
poll函数介绍
1. 包含头文件:<poll.h>
2. 函数原型:int poll ( struct pollfd * fdarray, unsigned long nfds, int timeout);
// 监听描述数组的元素
struct pollfd {
int fd; // 监听描述符
short events; // 测试事件
short revents; // 测试结果
};
3. 说明:相比于select函数,poll函数使用了结构体数组fdarray来表示监听描述符集合,该数组元素类型如上代码所示。当我们检索这个数组,我们可以知道有哪些描述符被监听,监听测试事件是什么,测试的结果又是什么。( 而在select函数的fdset描述符集合中,无法获知某位是不是被监听的描述符,这也就是下面的代码并不需要使用client数组的原因 )。
代码实现
#include "unp.h"
// 下头文件包含宏定义OPEN_MAX
#include <limits.h> int
main(int argc, char **argv)
{
int i, maxi, listenfd, connfd, sockfd;
int nready;
ssize_t n;
char buf[MAXLINE];
socklen_t clilen;
struct pollfd client[OPEN_MAX];
struct sockaddr_in cliaddr, servaddr; listenfd = Socket(AF_INET, SOCK_STREAM, ); bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT); Bind(listenfd, (SA *) &servaddr, sizeof(servaddr)); Listen(listenfd, LISTENQ); client[].fd = listenfd;
client[].events = POLLRDNORM;
// 清空监听描述符数组
for (i = ; i < OPEN_MAX; i++)
client[i].fd = -;
// 该变量表示已连接套接字描述符的最大数量( 曾经 )
maxi = ; for ( ; ; ) {
nready = Poll(client, maxi+, INFTIM); // 如果有监听描述符检测到可读数据的信号
if (client[].revents & POLLRDNORM) {
clilen = sizeof(cliaddr);
connfd = Accept(listenfd, (SA *) &cliaddr, &clilen);
#ifdef NOTDEF
printf("new client: %s\n", Sock_ntop((SA *) &cliaddr, clilen));
#endif // 登记刚刚获取到的已连接套接字描述符
// OPEN_MAX表示最多监听的描述符个数
for (i = ; i < OPEN_MAX; i++)
if (client[i].fd < ) {
client[i].fd = connfd;
break;
}
if (i == OPEN_MAX)
err_quit("too many clients"); // 设置监听测试事件
client[i].events = POLLRDNORM;
if (i > maxi)
maxi = i; // 如果信号已经处理完毕则自动进入下一次循环
if (--nready <= )
continue;
} for (i = ; i <= maxi; i++) {
if ( (sockfd = client[i].fd) < )
continue;
// 如果检测到可读或者发生错误的信号
if (client[i].revents & (POLLRDNORM | POLLERR)) {
if ( (n = read(sockfd, buf, MAXLINE)) < ) {
if (errno == ECONNRESET) {
#ifdef NOTDEF
printf("client[%d] aborted connection\n", i);
#endif
Close(sockfd);
client[i].fd = -;
} else
err_sys("read error");
} else if (n == ) {
#ifdef NOTDEF
printf("client[%d] closed connection\n", i);
#endif
Close(sockfd);
client[i].fd = -;
} else
Writen(sockfd, buf, n); // 如果检测到可读或者发生错误的信号
if (--nready <= )
break;
}
}
}
}
说明
如果从可移植性方面考虑或者有处理信号阻塞方面的需求( 要知道select还有个作为其升级版的pselect函数能够妥善处理信号阻塞 ),就还是得用select函数而不是poll函数。否则的话就随意了。
不为客户连接创建子进程的并发回射服务器( poll实现 )的更多相关文章
- 第二十篇:不为客户连接创建子进程的并发回射服务器(poll实现)
前言 在上文中,我使用select函数实现了不为客户连接创建子进程的并发回射服务器( 点此进入 ).但其中有个细节确实有点麻烦,那就是还得设置一个client数组用来标记select监听描述符集中被设 ...
- 第十九篇:不为客户连接创建子进程的并发回射服务器(select实现)
前言 在此前,我已经介绍了一种并发回射服务器实现.它通过调用fork函数为每个客户请求创建一个子进程.同时,我还为此服务器添加了自动消除僵尸子进程的机制.现在请想想,在客户量非常大的情况下,这种为每个 ...
- 不为客户连接创建子进程的并发回射服务器( select实现 )
前言 在此前,我已经介绍了一种并发回射服务器实现( 点此进入 ).它通过调用fork函数为每个客户请求创建一个子进程.同时,我还为此服务器添加了自动消除僵尸子进程的机制.现在请想想,在客户量非常大的情 ...
- socket编程之并发回射服务器2
承接上文:socket编程之并发回射服务器 为了让服务器进程的终止一经发生,客户端就能检测到,客户端需要能够同时处理两个描述符:套接字和用户输入. 可以使用select达到这一目的: void str ...
- socket编程之并发回射服务器
使用到的函数: // 子进程返回0,父进程返回子进程ID,出错返回-1 pid_t fork(void); pid_t wait(int *wstatus); // 最常用的option是WNOHAN ...
- socket编程之并发回射服务器3
在socket编程之并发回射服务器一文中,服务器采用多进程的方式实现并发,本文采用多线程的方式实现并发. 多线程相关API: // Compile and link with -pthread int ...
- 并发回射服务器的最基本实现思路( fork )
前言 一个服务器,通常会在一段时间内接收到多个请求.如果非要等到处理完一个请求再去处理下一个,势必会造成大部分用户的不满( 尤其当有某个请求需要占用大量时间时 ).如何解决这个问题?让处理这些用户请求 ...
- 服务器编程入门(11)TCP并发回射服务器实现 - 单线程select实现
问题聚焦: 当客户端阻塞于从标准输入接收数据时,将读取不到别的途径发过来的必要信息,如TCP发过来的FIN标志. 因此,进程需要内核一旦发现进程指定的一个或多个IO条件就绪(即输入已准备好被读取,或者 ...
- 服务器编程入门(10)TCP回射服务器实现 - 并发
问题聚焦: 在前面我们大概浏览了一下服务器编程需要掌握的一些知识和技术,以及架构思想. 实践,才是检验真理的唯一标准..从这节起我们将在这些技术的基础上,一步步实现以及完善一个服 ...
随机推荐
- 【前端学习笔记】2015-09-09~~~~nodejs中的require()和module.exports
nodejs中一个js文件就可以看做是一个模块 在node环境中,可以直接var a=require('模块路径以及不带扩展名的模块名') exports---module.exports 其中nod ...
- gulp前端自动化入门
一.从零开始搭建gulp前端自动化 1.首先安装nodejs 2.npm init 初始化 生成package.json 2.1 可以选装cnpm cnpm是淘宝提供的服务 安装:命令提示符执行npm ...
- 神秘的FrontCache
用jmap -histo的时候,发现堆内存中有很多奇怪的对象,其class name为 java.util.HashMap$FrontCache 跳转到HashMap的源码中,直接搜索FrontCac ...
- (4)ASP.NET HttpRequest 类
HttpRequest 类的主要作用是读取客户端在 Web 请求期间发送的 HTTP 值. https://msdn.microsoft.com/zh-cn/library/system.web.ht ...
- CCCC L2-024 部落【并查集】
https://www.patest.cn/contests/gplt/L2-024 首先在一行中输出这个社区的总人数.以及互不相交的部落的个数.随后对每一次查询,如果他们属于同一个部落,则在一行中输 ...
- BZOJ 4540 [Hnoi2016]序列 (单调栈 + ST表 + 莫队算法)
题目链接 BZOJ4540 考虑莫队算法. 这题难在$[l, r]$到$[l, r+1]$的转移. 根据莫队算法的原理,这个时候答案应该加上 $cal(l, r+1) + cal(l+1, r+1) ...
- [原创][FPGA]时钟分频之奇分频(5分频)
0. 简介 有时在基本模块的设计中常常会使用到时钟分频,时钟的偶分频相对与奇分频比较简单,但是奇分频的理念想透彻后也是十分简单的,这里就把奇分频做一个记录. 1. 奇分频 其实现很简单,主要为使用两个 ...
- 服务器SSL/TLS快速检测工具TLLSSLed
服务器SSL/TLS快速检测工具TLLSSLed 现在SSL和TLS被广泛应用服务器的数据加密中,如网站的HTTPS服务.所以,在渗透测试中如何快速检测服务器的SSL和TLS配置寻找安全漏洞,就显 ...
- Nessus虚拟机的几个问题解决办法
1.使用ppp的校园网或者家庭宽带无法通过桥接上网. 这时要把这俩网卡变成NAT模式就行. 2.国外下载插件包(或者过慢). 我这里贡献个高速链接.base64,懂得自然懂. c3NyOi8vTkRj ...
- JDBC_完整版
1,新建WEB项目:JDBC 2,导入驱动 将mysql-connector-java-5.0.8-bin.jar包放入web-inf目录下面的lib目录中 3,新建User类,放入entity包中 ...