多路IO转接服务器实现方法二:poll()函数

2023-05-16

相较于多路IO转接服务器实现方法一:select()函数,使用poll()函数的优点有

  1. 文件描述符的上限可以突破1024
  2. select()函数监听集合与返回的满足监听条件的集合为一个集合,而poll函数将监听集合与符合监听条件的集合实现了分离
  3. 搜索满足条件的文件描述符的范围缩小了

但,poll函数不能实现跨平台,只能在Linux平台上使用,而select()函数可以跨平台

poll()函数

函数原型

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

参数

  • fds:类型为struct pollfd的数组
    如果不想再监控某个文件描述符时,把pollfd中,fd设置为-1
    struct pollfd{
    	int fd;//文件描述符
    	short events;//监控的事件
    	short revents;//监控事件中满足条件返回的事件
    }
    
  • nfds:监控数组中有多少文件描述符需要被监控
  • timeout:毫秒级等待
    • -1:阻塞等
    • 0:立即返回,不阻塞进程
    • >0:等待指定毫秒数,如当前系统时间精度不够毫秒,向上取值

返回值

  • 成功:返回所监听的所有监听集合中满足条件的总数。
  • 失败:返回-1,并设置errno。

例子

#include <stdio.h>
#include <sys/socket.h>
#include <poll.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <ctype.h>

#define PORT 8888
#define IP "127.0.0.1"
#define MAXNUM 6
int main()
{
    //获得通信套接字
    int sfd = socket(AF_INET,SOCK_STREAM,0);

    //绑定
    struct sockaddr_in serv_addr;
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);
    inet_pton(AF_INET,IP,&serv_addr.sin_addr.s_addr);
    socklen_t serv_len = sizeof (serv_addr);
    int ret = bind(sfd,(struct sockaddr*)&serv_addr,serv_len);
    if(ret != 0){
        printf("bind error:%s\n",strerror(ret));
    }

    //监听
    listen(sfd,128);

    //初始化struct pollfd结构体数组,将sfd放入数组的0号位置
    struct pollfd client[MAXNUM];
    client[0].fd = sfd;
    client[0].events = POLLIN;

    for(int i = 1; i < MAXNUM; i++){
        client[i].fd = -1;
    }
    int maxi = 0;
    char buf[BUFSIZ];
    memset(buf,0,sizeof (buf));
    while(1){
        ret = poll(client,maxi+1,-1);

        //此时监听的sfd如果有读事件发生,说明有新的连接要建立,调用accept()函数
        if(client[0].revents & POLLIN){
            struct sockaddr_in clie_addr;
            socklen_t clie_len = sizeof (clie_addr);
            //返回客户端 cfd
            int cfd = accept(client[0].fd,(struct sockaddr*)&clie_addr,&clie_len);
            printf("%sconnected and port=%d\n",inet_ntop(AF_INET,&clie_addr.sin_addr.s_addr,buf,sizeof (buf)),
                   ntohs(clie_addr.sin_port));

            //将客户端文件描述符加入监听数组中即client[]中
            //找到数组中的空位置才能加入
            int i;
            for(i = 1; i < MAXNUM;i++){
                if(client[i].fd < 0){
                    client[i].fd = cfd;
                    break;
                }
            }
            //这里设置了最大的监听数为MAXNUM,如果超过了这个值就不再监听,退出
            if(i == MAXNUM){
                printf("too many connected...\n");
                exit(1);
            }

            //将cfd加入监听数组client[]中后,设置其监听属性,即是要监听他的读事件还是写事件异常事件
            client[i].events = POLLIN;//此处设置为监听他的读事件

            //将数组下标位置后移,其实就是现在一共实际要监听的文件描述符个数
            if(i > maxi){
                maxi = i;
            }

            //此处if语句条件满足要continue的原因是,假如ret中只有一个sfd时,说明客户端没有向服务端发送数据,所以跳出继续监听sfd的下一个连接
            if(--ret == 0){
                continue;
            }
        }
        //代码走到这里说明监听数组client[]中,有客户端在发数据了,接下来就是读数据并写回去
        int sockfd;
        int k;
        for(k = 1; k <= MAXNUM; k++){
            if((sockfd = client[k].fd) < 0){
                continue;
            }
            //k从1开始,就是跳过了第一个sfd,其余的客户端发送数据的文件描述符
            char rwbuf[BUFSIZ];
            memset(buf,0,sizeof (buf));
            if(client[k].revents & POLLIN){
                //如果满足 条件,开始读数据
                int len = read(sockfd,rwbuf,sizeof (rwbuf));
                if(len == 0){
                    //说明客户端关闭了
                    printf("client %d disconnected...\n",k);
                    close(sockfd);
                    client[k].fd = -1;
                }else if(len > 0){
                    //读到了数,将小写转换为大写
                    for(int i = 0; i< len; i++){
                        rwbuf[i] = toupper(rwbuf[i]);
                    }
                    write(sockfd,rwbuf,len);
                }
                if(--ret == 0){
                    break;
                }
            }
        }
    }
    close(sfd);
    return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

多路IO转接服务器实现方法二:poll()函数 的相关文章

  • 线程的同步机制

    方式一 xff1a 同步代码块 span class token keyword synchronized span span class token punctuation span 同步监视器 span class token punc
  • Java常用类总结

    一 字符串相关的类 String类及其常用方法 1 String声明为final的 xff0c 不可被继承 2 String实现了Serializable接口 xff1a 表示字符串是支持序列化的 xff1b 实现了Comparable接口
  • java获取两个字符串中最大相同字串

    span class token keyword import span span class token keyword static span java span class token punctuation span lang sp
  • jdk提供的4种注解

    元注解 xff1a 对现有的注解进行解释说明的注解 Retention xff1a 指定所修饰的Annotation的生命周期 xff1a SOURCE CLASS xff08 默认行为 xff09 RUNTIME xff0c 只有声明为R
  • Java中List接口常用方法

    List除了从Collection集合继承的方法外 xff0c List集合里添加了一些根据索引来操作集合元素的方法 xff1a 序号返回值函数作用1voidadd int index Object ele 在index位置插入ele元素2
  • 对Java中Class类的理解并获取Class实例

    关于java lang Class类的理解 类的加载过程 xff1a 程序经过javac exe命令以后 xff0c 会生成一个或多个字节码文件 class结尾 接着我们使用java exe命令对某个字节码文件进行解释运行 相当于将某个字节
  • 类加载器ClassLoader及应用

    类加载器ClassLoader span class token keyword public span span class token keyword class span span class token class name Cla
  • 创建运行时类的对象、调用运行时类的指定结构以及获取运行时类的完整结构

    创建两个类 一个注解 一个接口 用来准备测试 span class token keyword public span span class token keyword class span span class token class n
  • Lambda表达式基本使用的六种情况

    举例 xff1a o1 o2 gt Integer compare o1 o2 格式 xff1a lambda操作符 或 箭头操作符 左边 xff1a lambda形参列表 xff08 其实就是接口中的抽象方法的形参列表 xff09 右边
  • DBeaver登录Mysql所犯的低级错误

    1 简介 DBeaver是免费和开源 xff08 GPL xff09 为开发人员和数据库管理员通用数据库工具 2 安装DBeaver 3 DBeave连接MySQL 3 1 在DBeaver界面的左上角 xff0c 找到加号 xff0c 选
  • sql基础

    DB xff1a 数据库 database xff1a 存储数据的 仓库 它保存了一系列有组织的数据 DBMS xff1a 数据库管理系统 Database Management System 数据库是通过DBMS创建和操作的容器 SQL
  • SQL之DQL语言

    1 基础查询 语法 xff1a select 查询列表 from 表名 其中 xff1a 表中的字段 常量值 表达式 函数 查询字段 xff1a select 字段 多个字段中间逗号隔开 from 表名 查询常量值 xff1a select
  • Ubuntu中安装.deb格式的软件包

    使用dpkg命令进行安装 dpkg命令常用格式如下 xff1a sudo dpkg I iptux deb 查看iptux deb软件包的详细信息 xff0c 包括软件名称 版本以及大小等 xff08 其中 I等价于 info xff09
  • SQL之DDL(数据定义语言)

    1 库的管理 创建库 create database if not exists 库名 更改库的字符集 alter database 库名 character set gbk utf 8 删除库 drop database if exist
  • SQL之事务级别

    事务 xff1a 一个或一组sql语句组成一个执行单元 xff0c 这个执行单元要么全部执行 xff0c 要么全部不执行 事务的ACID属性 xff1a 原子性 原子性是指事务是一个不可分割的工作单位 xff0c 事务中的操作要么都发生 x
  • 动态数组的创建、插入、按值删除、按位值删除、销毁(C语言实现)

    dynamic h文件 xff1a span class token macro property span class token directive keyword pragma span once span span class to
  • 统计字母字符串中字符出现的次数(C语言实现)

    span class token macro property span class token directive keyword define span CRT SECURE NO WARNINGS span span class to
  • C语言实现strlen()函数

    方式一 xff1a span class token macro property span class token directive keyword define span CRT SECURE NO WARNINGS span spa
  • C语言gets()、fgets()、puts()、fputs()、strlen()函数

    gets 函数 xff1a 从屏幕获取一个字符串 xff0c 返回字符串的首地址 可以获取带有空格的字符串 不安全 char gets char s 参数 xff1a 用来存储字符串的空间地址 返回值 xff1a 返回实际获取到的字符串首地
  • tcp三次握手与四次挥手的简化流程

    控制字段 xff1a SYN 1 xff1a 请求建立连接控制字段 ACK 1 xff1a 数据信息确认控制字段 FIN 1 xff1a 请求断开连接控制字段 tcp三次握手过程 xff1a 第一次握手 xff1a 发送SYN请求建立连接控

随机推荐