多路复用IO、TCP并发模型

时分复用

CPU单核在同一时刻只能做一件事情,一种解决办法是对CPU进行时分复用(多个事件流将CPU切割成多个时间片,不同事件流的时间片交替进行)。在计算机系统中,我们用线程或者进程来表示一条执行流,通过不同的线程或进程在操作系统内部的调度,来做到对CPU处理的时分复用。这样多个事件流就可以并发进行,不需要一个等待另一个太久,在用户看起来他们似乎就是并行在做一样。

PC寄存器  程序计数器 代码执行到哪里了  程序下一条要执行什么。

有没有一种可以在单线程/进程中处理多个事件流的方法呢?一种答案就是IO多路复用。

因此IO多路复用解决的本质问题是在用更少的资源完成更多的事。

IO模型

  •     1、阻塞IO  
  •     2、非阻塞IO  EAGAIN  忙等待 errno
  •     3、信号驱动IO  SIGIO 用的相对少(了解)
  •     4、并行模型 进程,线程
  •     5, IO多路复用  select、poll、epoll

1、阻塞IO ===》最常用 默认设置

以管道读写为例子:
 

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>int main(int argc, const char *argv[])
{int ret = mkfifo("fifo",0666);if(-1 == ret){if(EEXIST == errno){}else{perror("mkfifo error");exit(1);}}int fd = open("fifo",O_RDONLY);if(-1 == fd){perror("open error");exit(1);}while(1){char buf[100] = {0};read(fd,buf,sizeof(buf));printf("fifo:%s\n",buf);bzero(buf,sizeof(buf));fgets(buf,sizeof(buf),stdin);printf("terminal:%s",buf);fflush(stdout);}close(fd);return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
int main(int argc, const char *argv[])
{int ret = mkfifo("fifo",0666);if(-1 == ret){if(EEXIST == errno){}else{perror("mkfifo failed");exit(1);}}int fd = open("fifo", O_WRONLY);if(-1 == fd){perror("open failed");exit(1);}while(1){char buf[100] = "hello,this is fifo test";write(fd,buf,strlen(buf));sleep(3);}close(fd);return 0;
}

2、非阻塞IO ===》在阻塞IO的基础上调整其为不再阻塞等待。


     在程序执行阶段调整文件的执行方式为非阻塞:
            ===》fcntl() ===>动态调整文件的阻塞属性

fcntl()

#include <unistd.h>
    #include <fcntl.h>
 

   int fcntl(int fd, int cmd, ... /* arg */ );


    功能:修改指定文件的属性信息。
    参数:fd 要调整的文件描述符
          cmd 要调整的文件属性宏名称
          ... 可变长的属性值参数。
    返回值:成功  不一定,看cmd
                  失败  -1;

int flag = fcntl(fd,F_GETFL);

fd 是要修改的文件描述符,可能是打开的文件、套接字或其他I/O设备。F_GETFL 是一个预定义的常量,告诉 fcntl 函数获取与文件描述符关联的标志。

fcntl(fd,F_SETFL ,flag | O_NONBLOCK );

 F_SETFL 常量用于设置文件描述符的标志。flag | O_NONBLOCK 是将获取到的当前标志与 O_NONBLOCK 常量进行按位或操作,目的是在现有标志的基础上添加非阻塞标志。

//noblock_fifo_r.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
int main(int argc, const char *argv[])
{int ret = mkfifo("fifo",0666);if(-1 == ret){if(EEXIST == errno){}else{perror("mkfifo error");exit(1);}}int fd = open("fifo",O_RDONLY);if(-1 == fd){perror("open error");exit(1);}int flag = fcntl(fd,F_GETFL);//获取当前文件描述符的标志:fcntl(fd,F_SETFL,flag|O_NONBLOCK);//设置文件描述符为非阻塞模式:flag = fcntl(0,F_GETFL);// 0 是标准输入的文件描述符 stdinfcntl(0,F_SETFL,flag|O_NONBLOCK);while(1){char buf[100] = {0};if(read(fd,buf,sizeof(buf))>0){printf("fifo:%s\n",buf);}bzero(buf,sizeof(buf));if(fgets(buf,sizeof(buf),stdin)){	printf("terminal:%s",buf);fflush(stdout);}}close(fd);return 0;
}
//noblock_fifo_w.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
int main(int argc, const char *argv[])
{int ret = mkfifo("fifo",0666);if(-1 == ret){if(EEXIST == errno){}else{perror("mkfifo failed");exit(1);}}int fd = open("fifo", O_WRONLY);if(-1 == fd){perror("open failed");exit(1);}while(1){char buf[100] = "hello,this is fifo test";write(fd,buf,strlen(buf));sleep(3);}close(fd);return 0;
}

TCP服务器和客户端的收发计数。

头文件:

#ifndef __HEAD_H__
#define __HEAD_H__#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <time.h>
#include <pwd.h>
#include <grp.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/in.h>
#endif

客户端:

#include "head.h"int CreateTcpClient(char *pip,int port)
{int ret = 0;int sockfd = 0;struct sockaddr_in seraddr;sockfd = socket(AF_INET,SOCK_STREAM,0);if(-1 == sockfd){perror("fail to socket");return -1;}seraddr.sin_family = AF_INET;seraddr.sin_port = htons(port);seraddr.sin_addr.s_addr = inet_addr(pip);ret = connect(sockfd,(struct sockaddr * )&seraddr,sizeof(seraddr));if(-1 == ret){perror("fail to connect");return -1;}return sockfd;
}int main(int argc, const char *argv[])
{int sockfd = 0;char tmpbuff[4096] = {0};int cnt = 0;ssize_t nsize = 0;sockfd = CreateTcpClient("192.168.95.131",50000);while(1){memset(tmpbuff,0,sizeof(tmpbuff));sprintf(tmpbuff,"cnt-----%d",cnt);cnt++;nsize = send(sockfd,tmpbuff,strlen(tmpbuff),0);if(-1 == nsize){perror("fail to send");return -1;}memset(tmpbuff,0,sizeof(tmpbuff));nsize = recv(sockfd,tmpbuff,sizeof(tmpbuff),0);if(nsize == 0){printf("be colsed!\n");return-1;}if(-1 == nsize){perror("fail to recv");return -1;}printf("RECV:%s\n",tmpbuff);}close(sockfd);return 0;
}

服务器:

#include"head.h"int CreateListenSocket(char *pip,int port)
{int ret = 0;int sockfd = 0;struct sockaddr_in seraddr;sockfd = socket(AF_INET,SOCK_STREAM,0);if(-1 == sockfd){perror("fail to socket");return -1;}seraddr.sin_family = AF_INET;seraddr.sin_port = htons(port);seraddr.sin_addr.s_addr = inet_addr(pip);ret = bind(sockfd,(struct sockaddr*)&seraddr,sizeof(seraddr));if(-1 == ret){perror("fail to bind");return -1;}ret = listen(sockfd,10);if(-1 == ret){perror("fail to listen");return -1;}return sockfd;
}int HandleTcpClient(int confd)
{char tmpbuff[4096] = {0};ssize_t nsize = 0;while(1){memset(tmpbuff,0,sizeof(tmpbuff));nsize = recv(confd,tmpbuff,sizeof(tmpbuff),0);if(-1 == nsize){perror("fail to recv");return -1;}else if(0 == nsize){return 0;}printf("%s\n",tmpbuff);sprintf(tmpbuff,"%s---echo",tmpbuff);nsize = send(confd,tmpbuff,strlen(tmpbuff),0);if(-1 == nsize){perror("faill to send");return -1;}}return nsize;
}int main(int argc, const char *argv[])
{int sockfd = 0;int confd = 0;sockfd = CreateListenSocket("192.168.95.131",50000);while(1){confd = accept(sockfd,NULL,NULL);if(-1 == confd){perror("fial to accept");return -1;}HandleTcpClient(confd);}close(confd);close(sockfd);return 0;
}

TCP并发模型  

        在服务器端如何高效地处理多个TCP连接,以实现高并发性能。

为什么 TCP需要并发模型而UDP不需要?

tcp是面向连接的,其中的accept()和recv()如果未收到数据都是会阻塞。

TCP:

1. 面向连接:TCP是面向连接的协议,意味着在数据传输开始前,需要先建立连接,这通常涉及到三次握手的过程。每个TCP连接都是独立的,需要单独管理。

2. 可靠性:TCP提供了可靠的数据传输,它确保数据按顺序到达,且不会丢失。这通过序列号、确认应答、重传机制和流量控制等机制实现。

3. 拥塞控制:TCP具有拥塞控制机制,以防止网络拥塞。当网络拥堵时,TCP会减慢数据发送速率。

UDP:由于UDP的无连接和不可靠特性,通常不需要像TCP那样精细的并发模型。当一个UDP服务器需要处理多个客户端时,它可以简单地接收数据报,处理后回应,而不需要维护每个连接的状态。因此,即使在处理大量并发请求时,UDP服务器的实现通常也较为简单,可能只需要一个线程或进程来处理所有数据报。

1.TCP多进程、多线程模型:

        多进程模型(Multi-process Model): 在这种模型中,每当一个新的连接请求到来时,服务器就会创建一个新的进程来处理这个连接。每个进程负责一个或多个连接,处理完后退出。这种方法的优点是每个连接都有独立的地址空间,错误不会互相影响,但是创建进程的开销较大,而且每个进程都需要消耗一定的系统资源,如内存和文件描述符。

     多线程模型(Multi-threaded Model): 与多进程模型类似,但使用线程代替进程。当新的连接请求到达时,服务器会在现有的线程池中选择一个线程来处理这个连接。线程的切换和上下文切换开销比进程要小,因此可以支持更高的并发数。但是线程共享相同的地址空间,所以需要小心处理线程安全问题。

    缺点:多进程和多线程的创建会带来资源开销,能够实现的并发量比较有限 。

 逻辑控制流在时间上的重叠叫做 并发。

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

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

相关文章

HarmonyOS 本地真机运行

目录 官网地址 1.开发工具设置签名 2.手机开启开发者模式 3.使用USB连接方式 4.使用无线调试连接方式 5.常见的问题 官网地址 使用真机运行应用 使用本地真机运行应用/服务 1.开发工具设置签名 官网应用/服务签名 1.左上角文件--项目结构-勾选自动生成签名-Sign in登录 2…

WEB前端08-综合案例(动态表格)

使用 HTML、CSS 和 JavaScript 创建动态表格 在本教程中&#xff0c;我们将创建一个动态表格&#xff0c;允许用户添加行、选择项目&#xff0c;并执行批量操作&#xff0c;如全选或删除选中的行。我们将通过 HTML、CSS 和 JavaScript 来实现这一功能。让我们逐步了解每个部分…

Vue前端工程化 安装Vue-Cli与node.js 最详细步骤(带图展示)

一、安装NodeJS 1.官网下载 https://nodejs.org/zh-cn 2.直接从百度网盘中提取安装 链接&#xff1a;https://pan.baidu.com/s/1OKhHZUwPCLamvd_08Vxx0g 提取码&#xff1a;61rw 3.开始安装 二、验证NodeJS环境变量 1.Win R 输入cmd打开控制面板 2.输入 node -v 如果出…

NVIDIA 全面转向开源 GPU 内核模块

NVIDIA 全面转向开源 GPU 内核模块 文章目录 NVIDIA 全面转向开源 GPU 内核模块支持的 GPU安装程序更改使用带有 CUDA 元包的包管理器 使用运行文件使用安装帮助脚本包管理器详细信息dnf&#xff1a;Red Hat Enterprise Linux、Fedora、Kylin、Amazon Linux 或 Rocky Linuxzypp…

程序员信息差,这个工具你必须知道

身为程序员&#xff0c;你是否也曾遇到过这样的情况&#xff1a;费尽心思搭建好服务器&#xff0c;开发好接口API&#xff0c;结果上线后却发现用户体验并不好&#xff0c;甚至还因为各种BUG忙得焦头烂额&#xff1f;别担心&#xff0c;你不是一个人。事实上&#xff0c;很多开…

用神经网络求解微分方程

微分方程是物理科学的主角之一&#xff0c;在工程、生物、经济甚至社会科学中都有广泛的应用。粗略地说&#xff0c;它们告诉我们一个量如何随时间变化&#xff08;或其他参数&#xff0c;但通常我们对时间变化感兴趣&#xff09;。我们可以了解人口、股票价格&#xff0c;甚至…

Python 使用TCP\UDP协议创建一个聊天室

server端代码&#xff1a; #encodingutf-8 # 服务端代码 import socketdef server():server_socket socket.socket(socket.AF_INET, socket.SOCK_STREAM)host socket.gethostname()port 12345server_socket.bind((host, port))server_socket.listen(5)print(等待客户端连接…

使用Gradle构建编译Spring boot 2.7.x

一、环境准备 JDK 1.8Spring boot 2.7.xGradle 7.5.1 (安装参考&#xff1a;win11安装Gradle)Idea 2023.1 二、源码导入gitee(可选) 按需导入。如果能科学上网&#xff0c;可跳过这一步。 为避免github访问不稳定问题&#xff0c;建议将对应的代码导入到gitee。然后通过git管…

内存泄漏详解

文章目录 什么是内存泄漏内存泄漏的原因排查及解决内存泄漏避免内存泄漏及时释放资源设置合理的变量作用域及时清理不需要的对象避免无限增长避免内部类持有外部类引用使用弱引用 什么是内存泄漏 内存泄漏是指不使用的对象持续占有内存使得内存得不到释放&#xff0c;从而造成…

【Java语法基础】1、变量、运算符、输入输出

1.变量、运算符、输入输出 跟C一样&#xff0c;先把必须写的框架写出来&#xff1a; package org.example; public class Main{public static void main(String[] args){//在里面写实际的代码} }变量 必须先定义&#xff0c;才能使用。与C、C差不多。 没有赋初值的变量无法…

windows网络应急排查

一、系统排查 msinfo32 #GUI显示的系统信息systeminfo #简单了解系统信息用户信息排查 排查恶意账号&#xff1a; 黑客喜欢建立相关账号用作远控: 1.建立新账号2.激活默认账号3.建立隐藏账号(windows中账号名$)cmd方法 net user #打印用户账号信息 ---看不到$结尾的隐藏账…

Linux - 进程的概念、状态、僵尸进程、孤儿进程及进程优先级

目录 进程基本概念 描述进程-PCB task_struct-PCB的一种 task_struct内容分类 查看进程 通过系统目录查看 通过ps命令查看 通过系统调用获取进程的PID和PPID 通过系统调用创建进程- fork初始 fork函数创建子进程 使用if进行分流 Linux进程状态 运行状态-R 浅度睡眠状态-S…

Apache Filnk----入门

文章目录 Flink 概述Flink 是什么有界流和无界流有状态流处理Flink 特点Flink vs SparkStreamingFlink 分层API Flink 快速上手WordCount 代码编写批处理流处理读取socket文本流 Flink 概述 Flink 是什么 有界流和无界流 无界数据流: 有定义流的开始&#xff0c;但没有定义流…

ts一些解决vscode飘红的方法

1、查看是否有些ts的数据类型定义问题&#xff0c;属性缺少或者属性类型不对 把对应属性加上即可 2、在飘红的代码前面设置// ts-ignore忽略此行校验&#xff08;不过一般不建议用这个方法&#xff09; 3、移除高版本不用的属性&#xff08;版本属性兼容问题&#xff09; 原因…

PP-Human行为识别(RTSP协议视频流实时检测)

基于PaddleDetection本地实现PP-Human行为识别模块&#xff08;RTSP协议视频流实时检测&#xff09; 项目介绍环境准备1. Anaconda 创建环境2. 获取 PaddleDetection3. 获取 [MediaMTX](https://github.com/bluenviron/mediamtx/releases/tag/v1.8.4)4. FFmpeg 获取5. VLC 获取…

.NET开源、简单、实用的数据库文档生成工具

前言 今天大姚给大家分享一款.NET开源&#xff08;MIT License&#xff09;、免费、简单、实用的数据库文档&#xff08;字典&#xff09;生成工具&#xff0c;该工具支持CHM、Word、Excel、PDF、Html、XML、Markdown等多文档格式的导出&#xff1a;DBCHM。 支持的数据库 Sq…

IEEE官方列表会议 | 第三届能源与环境工程国际会议(CFEEE 2024)

会议简介 Brief Introduction 2024年第三届能源与环境工程国际会议(CFEEE 2024) 会议时间&#xff1a;2024年12月2日-4日 召开地点&#xff1a;澳大利亚凯恩斯 大会官网&#xff1a;CFEEE 2024-2024 International Conference on Frontiers of Energy and Environment Engineer…

Android APP 音视频(01)MediaCodec解码H264码流

说明&#xff1a; 此MediaCodec解码H264实操主要针对Android12.0系统。通过读取sd卡上的H264码流Me获取视频数据&#xff0c;将数据通过mediacodec解码输出到surfaceview上。 1 H264码流和MediaCodec解码简介 1.1 H264码流简介 H.264&#xff0c;也被称为MPEG-4 AVC&#xff…

uni-app 影视类小程序开发从零到一 | 开源项目分享

引言 在数字娱乐时代&#xff0c;对于电影爱好者而言&#xff0c;随时随地享受精彩影片成为一种日常需求。分享一款基于 uni-app 开发的影视类小程序。它不仅提供了丰富的影视资源推荐&#xff0c;还融入了个性化知乎日报等内容&#xff0c;是不错的素材&#xff0c;同时对电影…

就业管理功能概述:构建智慧校园企业招聘平台

在智慧校园整体解决方案中&#xff0c;就业管理模块连接着学校与企业两端&#xff0c;更成为学生们步入社会、开启职业生涯梦想的关键门户。这一功能的核心价值&#xff0c;在于它如何巧妙地运用科技的力量&#xff0c;简化招聘流程&#xff0c;提升招聘效率&#xff0c;同时为…