多路复用——poll

news2024/10/8 11:31:50

         在之前我们说过TCP的模型,用户可以通过连接服务器从而通过服务器去加载服务端对应功能的文件来达到通信,但是我们知道,一个用户加载文件需要一个进程,在Linux中,一个进程就要占用4G的虚拟内存,如果在并发量高的情况下,很明显服务器是不堪重负的。下面来讲解决方案即多路复用技术。

        多路复用,举个例子就好比把多条狭窄的乡间小路修成一条双向16车道的快速路,即在这条大路上去进行网络通信。多路复用技术的核心就在于在单个网络信道上传输多个网络信号,能能大幅提高通信效率,并且能够很大程度上降低服务器的负担。

下面我们用TCP作为通信模型来看多路复用的第二种 I/O 机制,即poll:

服务端如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <poll.h>

int add_fds(struct pollfd *fds, int nfds, int fd, short events)
{
    for (int i = 0; i < nfds; i++)
    {
        if(0==fds[i].fd)
        {
            fds[i].fd=fd;
            fds[i].events=events;
            return 0;
        }
    }
    return -1;
}

//tcp server 只有server端能用多路复用
int main(int argc, char *argv[])
{
    //创建socket
    int svr_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (svr_fd < 0)
     {
        perror("socket");
        return -1;
    }
    //准备通信地址
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(8888);
    addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    socklen_t addrlen=sizeof(addr);
    //绑定地址
    if (bind(svr_fd, (struct sockaddr*)&addr, addrlen))
    {
        perror("bind");
        return -1;
    }
    //监听连接
    if (listen(svr_fd, 10))
    {
        perror("listen");
        return -1;
    }
    //创建pollfd数组并初始化
    struct pollfd *fds=calloc(sizeof(struct pollfd), 10);
    //设置[0]位置要监听的描述符和事件
    fds[0].fd=svr_fd;
    fds[0].events=POLLIN;
    //定义超时时间
    int timeout=10000;

    char buf[1024];
    size_t buf_size=sizeof(buf);

    while (1)
    {
        int ret=poll(fds, 10, timeout);
        if (ret == 0) continue; //超时
        if (ret < 0)
        {
            perror("poll");
            return -1;
        }
        //判断[0]位置是否有读事件产生
        if (fds[0].revents & POLLIN)
        {
            //接受连接
            int cli_fd=accept(svr_fd, (struct sockaddr*)&addr, &addrlen);
            if(cli_fd>0)
            {
                //把客户端的socket描述符添加到pollfd数组的空位置,并设置事件
                if(add_fds(fds, 10, cli_fd, POLLIN))
                {
                    printf("客户端数量已满\n");
                }
            }
        }
        else
        {
            //遍历pollfd数组,判断其它位置是否有读事件产生
            for (int i = 1; i < 10; i++)
            {
                if (!fds[i].revents & POLLIN) continue;
                int ret=recv(fds[i].fd, buf, buf_size, 0);
                if (ret <= 0||0==strcmp(buf, "quit"))
                {
                    printf("客户端 %d 退出\n", fds[i].fd);
                    fds[i].fd=0;
                    fds[i].events=0;
                    continue;
                }
                printf("recv:%s bits:%d\n", buf, ret);
                strcat(buf, ":return");
                ret=send(fds[i].fd, buf, strlen(buf)+1, 0);
                if (ret <= 0)
                {
                    printf("客户端 %d 退出\n", fds[i].fd);
                    fds[i].fd=0;
                    fds[i].events=0;
                    continue;
                }
            }
        }
    }

	return 0;
}

客户端如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/select.h>


typedef struct sockaddr *SP;

int main(int argc,const char* argv[])
{
	//创建socket
	int cli_fd=socket(AF_INET,SOCK_STREAM,0);
	if(cli_fd<0)
	{
		perror("socket");
		return -1;
	}
	//准备通信地址
	struct sockaddr_in addr={};
	addr.sin_family=AF_INET;
	addr.sin_port=htons(8888);
	addr.sin_addr.s_addr=inet_addr("127.0.0.1");
	socklen_t addrlen=sizeof(addr);
	//连接服务器
	if(connect(cli_fd,(SP)&addr,addrlen))
	{
		perror("connect");
		return -1;
	}

	char buf[4096];
	size_t buf_size=sizeof(buf);
	while(1)
	{
		//发送请求
		printf(">>>>>");
		scanf("%s",buf);
		int ret=send(cli_fd,buf,strlen(buf)+1,0);
		//ret=write(cli_fd,buf,strlen(buf)+1);
		if(ret<=0)
		{
			printf("服务器正在升级,请稍后重试\n");
			break;
		}
		if(0==strcmp("quit",buf))
		{
			printf("通信结束\n");
			break;
		}
		//接收请求
		//int ret=read(cli_fd,buf,buf_size);
		ret=recv(cli_fd,buf,buf_size,0);
		if(ret<=0)
		{
			printf("服务器正在维护,请稍候重试\n");
			break;
		}
		printf("read:%s bits:%d\n",buf,ret);
	}
		
	return 0;
}

over

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

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

相关文章

24.10.7(线段树合并,分裂,扫描线,字符串哈希)

星期一&#xff1a; 昨晚熬夜场的div2总算是不负有心人&#xff0c;到C都比较简单&#xff0c;出C后我也没有run的想法&#xff0c;一直在看D&#xff0c;最后5min的时间ac&#xff0c;小小上了波分 贴cf round976 div2 D cf传送门 题意&a…

从学习Java到学习AI大模型,我为什么选择的后者???

我为什么从Java转到AI大模型 在编程的海洋里&#xff0c;Java一直是我信赖的“小船”&#xff0c;载着我航行在代码的世界中。然而&#xff0c;随着行业的不断发展和变化&#xff0c;我开始感受到了一丝的迷茫和不安。我开始担心&#xff0c;随着技术的不断更新&#xff0c;Ja…

银河麒麟桌面操作系统V10 SP1:取消安装应用的安全授权认证

银河麒麟桌面操作系统V10 SP1&#xff1a;取消安装应用的安全授权认证 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 使用银河麒麟V10 SP1安装应用时&#xff0c;若频繁遇到安全授权认证提示&#xff0c;可按以下步骤设置&#xff1a; 打开…

操作系统 | 学习笔记 | 王道 | 4.3 文件系统

4.3 文件系统 4.3.1 文件系统结构 文件系统(File system)提供高效和便捷的磁盘访问&#xff0c;以便允许存储、定位、提取数据。 用一个例子来辅助记忆文件系统的层次结构&#xff1a; 假设某用户请求删除文件"D:/工作目录/学生信息.xIsx"的最后100条记录。 用户需…

Linux——磁盘分区、挂载

Linux 分区 原理介绍 原理图如下 当我们在/home目录下新建一个文件a.txt时&#xff0c;该文件实际上是存放在硬盘B的分区1中的&#xff0c;这就是图里说的&#xff0c;当进入某个目录&#xff0c;可以进入到该目录下挂载的分区里的意思 硬盘说明 应用实例&#xff1a;挂载一个…

镁稀土中间合金的耐腐蚀性

镁稀土中间合金&#xff0c;也称作镁稀土合金&#xff0c;是一种重要的合金材料&#xff0c;由镁、稀土元素(如镧、铈、镨、钕、钷、钐、铕、钆、铽、镝、钬、铒、镱、镥等)以及其他可能的金属元素(如铝、锶、锆、钙等)组成。以下是对镁稀土中间合金的详细介绍&#xff1a; 一、…

六、索引的数据结构

文章目录 1. 为什么使用索引2. 索引及其优缺点2.1 索引概述2.2 优点2.3 缺点3. InnoDB中索引的推演3.1 索引之前的查找3.1.1 在一个页中的查找3.1.2 在很多页中查找3.2 设计索引3.2.1 一个简单的索引设计方案3.2.2 InnoDB中的索引方案3.3 常见索引概念3.3.1 聚簇索引3.3.2 二级…

CPU Study - Recovery when Prediction Fails

参考来源&#xff1a;《超标量处理器设计》—— 姚永斌 分支预测失败时&#xff0c;这条分支指令之后的所有指令都处在了错误的路径上&#xff08;mis-prediction&#xff09;。 这些指令都会被抹除掉 &#xff0c;从而造成很多bubble&#xff0c;降低处理器性能&#xff0c;称…

数学概念算法-打印100以内的素/质数

素数&#xff1a;只能被1和自己整除的数 暴力破解 埃氏筛选 找到第一个数字&#xff0c;如果它是素数&#xff0c;则把它的倍数全部划掉 比如数字2是素数&#xff0c;那么 4,6,8,10,12。这些数字肯定不是素数&#xff0c;所以不用再考虑&#xff0c;直接划掉即可 第二步&#…

ROS理论与实践学习笔记——3 ROS运行管理之ROS话题名称设置

名称重映射是为名称起别名&#xff0c;为名称添加前缀&#xff0c;该实现比节点重名更复杂些&#xff0c;不单是使用命名空间作为前缀、还可以使用节点名称最为前缀。两种策略的实现途径有多种: &#xff08;1&#xff09;rosrun 命令 &#xff08;2&#xff09;launch 文件 …

camody卡魔迪-准备新一年双十一推出iPhone快充充电宝

随着双十一购物节的临近&#xff0c;各大品牌纷纷推出创新产品以吸引消费者的目光。近日&#xff0c;知名科技品牌Camody卡魔迪宣布将在今年双十一期间推出一款全新的iPhone快充充电宝。这款充电宝不仅具备快速充电功能&#xff0c;还兼具时尚设计和便携性&#xff0c;预计将成…

ArcGIS中分区统计栅格值前需要进行投影吗(在投影坐标系下进行吗),为什么?

最近&#xff0c;我接到了一个分区统计栅格数值前需要进行投影&#xff0c;或者说是必须需要在投影坐标系下进行吗的咨询。 答案是不需要刻意去变。 但是他又说他把地理坐标系下分区统计结果与投影坐标系下的分区统计结果分别做了一遍&#xff0c;并进行了对比&#xff0c;两个…

通过docker安装thingsboard需要的postgresql数据库

1、下载docker的包 docker run --name postgresql -e POSTGRES_PASSWORDXXX123 -d registry.openanolis.cn/openanolis/postgres:10.21-8.6 进入postgresql&#xff0c;创建数据库 [rootlocalhost ~]# docker exec -it postgresql bash [root0940f42b2263 /]# su - postgre…

9.10Mean-Shift分割算法

基本概念 Mean-Shift 分割算法是一种非参数的特征空间点集的迭代查找算法&#xff0c;主要用于估计概率密度函数的模式。在计算机视觉中&#xff0c;它常用于颜色图像分割和目标跟踪。它通过迭代地移动每个数据点到其邻域内密度最大的地方&#xff0c;从而找到数据点的模式&am…

基于单片机的非接触智能测温系统设计

本设计主要由单片机STC8A8K64S4A12、OLED显示屏、非接触式测温模块MLX9061、无线通讯模块ESP8266以及声光报警模块等构成。系统通过非接触式测温模块MLX9061测量当前人员温度&#xff0c;温度通过OLED显示屏进行实时显示&#xff0c;当被测温度高于阈值&#xff0c;声光报警模块…

力扣16~20题

题16&#xff08;中等&#xff09;&#xff1a; 思路&#xff1a; 双指针法&#xff0c;和15题差不多&#xff0c;就是要排除了&#xff0c;如果total<target则排除了更小的&#xff08;left右移&#xff09;&#xff0c;如果total>target则排除了更大的&#xff08;rig…

java语言基础案例-cnblog

java语言基础案例 象棋口诀 输出 package nb;public class XiangQi {public static void main(String[] args) {char a 马;char b 象;char c 卒;System.out.println(a"走日"b"走田""小"c"一去不复还");} }输出汇款单 package nb…

在java中使用redis

Redis Java使⽤ 引入依赖 Java 操作redis的客⼾端有很多.其中最知名的是jedis. 创建maven项⽬,把jedis的依赖拷⻉到pom.xml中 <!-- https://mvnrepository.com/artifact/redis.clients/jedis --> <dependency><groupId>redis.clients</groupId><…

机房空调远程控制-Thingsboard MQTT 接口说明

一、 概述 为实现节能环保需求&#xff0c;拓扑未来公司推出轻量级&#xff0c;使用简单的远程空调控制解决方案。该方案集成了现场环境温湿度采集功能&#xff0c;设备管理功能&#xff0c;远程控制功能。支持本地自动控制模式和远程控制模式&#xff0c;自动模式下&#xff…

Chromium 如何查找已经定义好的mojom函数实现c++

进程通信定义通常都是用.mojom文件或者idl文件格式 以content\common\frame.mojom里面的BeginNavigation函数为例。 一、如何查找BeginNavigation函数定义&#xff0c;在vscode里面直接搜索BeginNavigation&#xff0c;过滤条件 *.idl,*.mojom,*.cc 效果&#xff1a; 这样…