Linux select开发服务端

多路IO技术:select,同时监听多个文件描述符,将监控的操作交给内核去处理。

数据类型fd_set:文件描述符集合。

 int select(int nfds, fd_set *readfds, fd_set *writefds,
                  fd_set *exceptfds, struct timeval *timeout);

函数介绍:委托内核监控该文件描述符对应的写,读或者错误事件的发生。

参数说明:

nfds:最大的文件描述符+1;

readfds:读集合,是一个传入传出参数

 传入:指的是告诉内核哪些文件描述符需要监控

 传出:指的是内核告诉应用程序哪些文件描述符发生了变化(是否有可读事件发生)

writefds:写集合,是一个传入传出参数

 传入:指的是告诉内核哪些文件描述符需要监控

 传出:指的是内核告诉应用程序哪些文件描述符发生了变化

exceptfds:传入传出参数,一般表示异常事件;

Timeout:

超时时间:

NULL:表示永久阻塞,直到有事件发生

0:表示不阻塞,不管有没有事件发生,都回立刻返回

>0:表示阻塞的时长,若超过时长会立刻返回

返回值:

成功返回发生变化的文件描述符个数。

void FD_CLR(int fd, fd_set *set);

说明:将fd从set集合中移除;


       int  FD_ISSET(int fd, fd_set *set);
说明:判断fd是否在set集合中       

void FD_SET(int fd, fd_set *set);

说明:将fd添加到set中


       void FD_ZERO(fd_set *set);

说明:将set清零

使用select的开发服务端大致流程:

1 创建socket,获取监听文件描述符lfd---socket();

2 设置端口复用---setsockopt();

3 将lfd与IP,PORT绑定---bind();

4 设置监听---listen();

5 fd_set readfds;//定义文件描述符集

FD_ZERO(&readfds);//清零

 将lfd加入到readfds集合中---FD_SET(lfd,&readfds);

6 fd_set tmpfds;//定义一个临时文件描述符集
maxfd = lfd;
while (1)
{
    tmpfds = readfds;//赋值
    nready = select(maxfd,&tmpfds,NULL,NULL,NULL);//传出修改的tmpfds(有哪些可读事件)
    if(nready<0)
    {
        if (errno == EINTR)//被信号中断
        {
            continue;
        }
        break;
    }
    //可读事件有两种:
    //1 客户端连接到来--->监听文件描述符lfd发生变化
    if (FD_ISSET(lfd, &tmpfds))
    {
      //接收新的客户端连接请求
        cfd = accept(lfd, NULL, NULL);
        //将cfd加入到readfds集合中
        FD_SET(cfd, &readfds);

        if (maxfd < cfd)
        {
            maxfd = cfd;//修改内核监控的文件描述符的范围
        }

        if (--nready == 0)
        {
            continue;//只有一个可读事件且已经执行完,就没必要继续执行下去
        }
    }
    //有客户端发数据过来
    for (i = lfd + 1; i <= maxfd; i++)
    {
        if (FD_ISSET(i, &tmpfds))//看那个通信描述符发生变化
        {
                //读数据
                int n = read(i, buf, sizeof(buf));//read函数不会阻塞,因为肯定有数据发过来
                if (n <= 0)
                {
                    close(i);
                    //将文件描述符i从内核中去除
                    FD_CLR(i, &readfds);
                }
                write(i, buf, strlen(buf));
        }
    }
    close(lfd);
    return 0;
}

完整代码:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <errno.h>
#include<ctype.h>
int main()
{//int socket(int domain, int type, int protocol);int lfd=socket(AF_INET,SOCK_STREAM ,0);if(lfd<0){perror("socket error");return -1;}// int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);int opt=1;setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(int));//设置端口复用//int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);struct sockaddr_in sev;sev. sin_family=AF_INET;sev. sin_port=htons(8888);inet_pton(AF_INET,"192.168.230.130",&sev.sin_addr.s_addr);int ret=bind(lfd,(struct sockaddr*)&sev,sizeof(sev));if(ret<0){perror("bind error");return -1;}ret=listen(lfd,128);if(ret<0){perror("listen error");return -1;}//int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);int maxfd=lfd;//定义最大fdfd_set readfds;//定义一个读文件描述符集FD_ZERO(&readfds);//清零FD_SET(lfd,&readfds);//加入readfds让内核监听lfdfd_set tmpfds;//定义一个传出读文件描述符集FD_ZERO(&tmpfds);int cfd;//通信描述符int i;int j;int n;char buf[64];int nready;//定义可读事件的数量while(1){tmpfds=readfds;
//让tmpfds成为传入传出参数
//输入:告诉内核要监听哪些文件描述符
//输出:内核告诉你有哪些文件描述符发生变化nready=select(maxfd+1,&tmpfds,NULL,NULL,NULL);if(nready<0){if(errno==EINTR)//被信号打断的错误不视为错误{continue;}else {break;}}if(FD_ISSET(lfd,&tmpfds))//判断lfd是否发生变化,若变化说明有客户端连接{cfd=accept(lfd,NULL,NULL);//接受连接,获取一个通信文件描述符if(maxfd<cfd){maxfd=cfd;//修改最大的maxfd}FD_SET(cfd,&readfds);//将cfd加入readfds,让内核监控是否变化if(--nready==0)//为真说明只有一个可读事件,继续循环{continue;}}for(i=lfd+1;i<=maxfd;i++){if(FD_ISSET(i,&tmpfds))//判断cfd是否发生变化,若变化则说明客户端发信息{memset(buf,0x00,sizeof(buf));n=read(i,buf,sizeof(buf));if(n<=0){printf("read error or client closer,n==[%d]\n",n);close(i);//关闭文件描述符FD_CLR(i,&readfds);//从内核中移除,取消监控continue;//继续循环}printf("n==[%d],buf==[%s]\n",n,buf);for(j=0;j<n;j++){buf[j]=toupper(buf[j]);}write(i,buf,n);if(--nready==0)//减少循环次数{break;}}}}close(lfd);return 0;
}

思考:如果有效的通信文件描述符过少,会让循环的次数变多。

优化方法:

int fd[100];

for()

{

fd[i]=-1;//先把内容都初始化为-1,证明没被占用

}

select优点:
 

1 一个进程可以支持多个客户端

2 select支持跨平台

select缺点:

1 代码编写困难

2 会涉及用户区到内核区来回拷贝

3 当客户端多个连接,但少数活跃,select效率低

4 最多支持1024个客户端连接 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/731202.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

态势感知的扭曲

态势感知中的扭曲是指由于各种原因导致对某些信息的感知出现偏差或错误的情况。扭曲可能是由于观察者的主观因素、信息来源的局限性、信息传递的失真等引起的。 在态势感知中&#xff0c;观察者的主观因素可能导致扭曲。例如&#xff0c;观察者的个人偏见、情绪状态、经验背景等…

5.53 BCC工具之dbslower.py解读

一,工具简介 dbstat用于追踪由MySQL或PostgreSQL数据库进程执行的查询,并显示查询延迟的直方图。 二,代码示例 #!/usr/bin/env pythonfrom bcc import BPF, USDT import argparse import subprocess from time import sleep, strftimeexamples = """dbsta…

挑战杯 基于深度学习的视频多目标跟踪实现

文章目录 1 前言2 先上成果3 多目标跟踪的两种方法3.1 方法13.2 方法2 4 Tracking By Detecting的跟踪过程4.1 存在的问题4.2 基于轨迹预测的跟踪方式 5 训练代码6 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于深度学习的视频多目标跟踪实现 …

软考高级:系统工程生命周期方法(计划驱动方法、渐进迭代式方法等)概念和例子

作者&#xff1a;明明如月学长&#xff0c; CSDN 博客专家&#xff0c;大厂高级 Java 工程师&#xff0c;《性能优化方法论》作者、《解锁大厂思维&#xff1a;剖析《阿里巴巴Java开发手册》》、《再学经典&#xff1a;《Effective Java》独家解析》专栏作者。 热门文章推荐&am…

如何在Ubuntu系统部署DbGate数据库管理工具并结合cpolar内网穿透远程访问

文章目录 1. 安装Docker2. 使用Docker拉取DbGate镜像3. 创建并启动DbGate容器4. 本地连接测试5. 公网远程访问本地DbGate容器5.1 内网穿透工具安装5.2 创建远程连接公网地址5.3 使用固定公网地址远程访问 本文主要介绍如何在Linux Ubuntu系统中使用Docker部署DbGate数据库管理工…

web组态

演示地址 &#xff1a;by组态[web组态插件] 这是一款可以嵌入到任何项目组态插件&#xff0c;功能全面&#xff0c;可根据自己的项目需要进行二次开发&#xff0c;能大大的节省在组态上的开发时间&#xff0c;代码简单易懂。 一、数据流向图及嵌入原理 数据流向 嵌入原理 …

IPD是流程界的阳明先生

这个说法是不是很有趣呢&#xff01;IPD&#xff08;Integrated Product Development&#xff0c;集成产品开发&#xff09;是一种在产品开发领域广泛应用的流程方法&#xff0c;它强调跨职能团队的协作、迭代开发和以市场需求为导向的设计。 将 IPD 与阳明先生进行类比&#…

深度神经网络 基本知识 记录

资料&#xff1a;https://www.bilibili.com/video/BV1K94y1Z7wn/?spm_id_from333.337.search-card.all.click&vd_source14a476de9132ba6b2c3cbc2221750b99 计划&#xff1a;3~4天 注&#xff1a;网课讲的内容比较糅杂&#xff0c;记录的内容可能会出现重复 杂 人工智能…

c++ primer中文版第五版作业第十七章

仓库地址 文章目录 17.117.217.317.417.517.617.717.817.917.1017.1117.1217.1317.1417.1517.1617.1717.1817.1917.2017.2117.2217.2317.2417.2517.2617.2717.2817.2917.3017.3117.3217.3317.3417.3517.3617.3717.3817.39 17.1 tuple<int,int,int> it(10,20,30) 17.2 …

安全加速SCDN是服务器防御攻击较佳方案

国家互联网应急中心的数据研究显示&#xff0c;基于漏洞、病毒、未知威胁的攻击正日益频繁且智能化&#xff0c;网络安全的防护难度也与日俱增&#xff0c;未来应用层攻击将成为主流。互联网飞速发展之余&#xff0c;对于网络安全的需求也越来越大&#xff0c;网络攻击的手段也…

<商务世界>《第8课 Leads——MQL——SQL——商机——成交》

1 各种概念 英文缩写概念Traffic流量Leads潜在客户&#xff0c;销售线索&#xff1b;简称潜在线索MQLMarketing-Qualified Leads市场认可线索SQLSales-Qualified Leads销售认可线索OPPOpportunity商机Account成单客户 2 线索到商机 一般企业会把自身线索进行如下的划分&…

【电工学笔记】上册第一、二章

电工学 上次考试败在了单位&#xff0c;这次单位 一定要记熟。 第一章 电源或信号源的电压或电流称为激励,它推动电路工作; 由激励所产生的电压和电流称为响应。 复杂电路中,一般无法事先判断某个支路电流的 实际方向或者某个电路元件电压的实际方向 140V/4算不出总电阻的 …

Linux setup命令教程:如何配置系统设置和硬件(附实例详解和注意事项)

Linux setup命令介绍 setup 命令用于配置系统的硬件和软件设置。它允许用户在安装后更改系统设置&#xff0c;例如键盘布局、时区、网络配置等。此命令通常在安装新系统后运行&#xff0c;但也可以在之后随时使用。 Linux setup命令适用的Linux版本 setup 命令在不同的Linux…

数据结构面试常见问题

数据结构面试常见问题 什么是 AVL 树&#xff1f;什么是红黑树&#xff1f;AVL 树和红黑树的区别&#xff1f;B 树和B 树的区别&#xff1f;排序有哪些分类&#xff1f;直接插入排序的原理&#xff1f;希尔排序的原理&#xff1f;直接选择排序的原理&#xff1f;堆排序的原理&a…

vue3的开发小技巧

「总之岁月漫长&#xff0c;然而值得等待。」 目录 父组件调用子组件函数如何访问全局api 父组件调用子组件函数 ref, defineExpose //父组件 代码 <child ref"ch">this.$refs.ch.fn();//子组件 函数抛出 const fn () > { }; defineExpose({ fn });如何…

考研复习C语言初阶(3)

目录 一.函数是什么? 二.C语言中函数的分类 2.1库函数 2.2自定义函数 三.函数的参数 3.1实际参数&#xff08;实参&#xff09; 3.2 形式参数&#xff08;形参&#xff09; 四.函数的调用 4.1 传值调用 4.2 传址调用 五. 函数的嵌套调用和链式访问 5.1 嵌套调用 5…

瑞芯微 | I2S-音频基础分享

1. 音频常用术语 名称含义ADC&#xff08;Analog to Digit Conversion&#xff09;模拟信号转换为数字信号AEC&#xff08;Acoustic Echo Cancellor&#xff09;回声消除AGC&#xff08;Automatic Gain Control&#xff09;自动增益补偿&#xff0c;调整MIC收音量ALSA&#xf…

Jmeter常用组件的使用场景

一.在一段时间内持续发送请求 此场景可以用于稳定性测试&#xff0c;在稳定性测试中&#xff0c;通常需要持续压测几个小时甚至几天时间&#xff0c;查看接口是否有报错&#xff0c;或者cpu、内存会上涨&#xff0c;此时就需要通过控制持续时间来达到此目的。 1.创建线程组&am…

基于SSM的校园疫情管理系统的设计与实现(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的校园疫情管理系统的设计与实现&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;…

powershell远程拷贝文件到windows 服务器

在PowerShell中&#xff0c;如果你要在本地机器和远程Windows服务器之间拷贝文件&#xff0c;可以使用Copy-Item命令配合Invoke-Command&#xff08;对于远程执行&#xff09;或New-PSSession&#xff08;用于创建持久会话后传输文件&#xff09;。这里是一个使用Copy-Item通过…