实现并发网络服务器

news2024/12/28 21:11:05

一,网络服务器

1.单循环网络服务器 —— 同一时刻只能处理一个客户端任务

2.并发服务器 —— 同一时刻能处理多个客户端任务

二,并发服务器

1.多线程

2.IO多路复用

3.多进程

三,IO模型

1.阻塞IO 

阻塞IO(Blocking IO)是一种传统的IO操作模式,在这种模式下,当一个IO操作(如读、写)执行时,如果不能立即完成,程序会暂停执行,直到该IO操作完成。类似于fgets, scanf, read, recv, getchar函数

实例

阻塞read.c
#include "head.h"


int main(int argc, const char *argv[])
{
	char buff[1024] = {0};
	mkfifo("./myfifo", 0664);
	
	int fifofd = open("./myfifo", O_RDONLY);
	if (-1 == fifofd)
	{
		perror("fail open fifo");
		return -1;
	}

	while (1)
	{
		fgets(buff, sizeof(buff), stdin);
		printf("STDIN : %s\n", buff);

		memset(buff, 0, sizeof(buff));
		read(fifofd, buff, sizeof(buff));
		printf("FIFO : %s\n", buff);
	}
	
	close(fifofd);

	return 0;
}
阻塞write.c
#include "head.h"


int main(int argc, const char *argv[])
{	
	mkfifo("./myfifo", 0664);
	
	int fd = open("./myfifo", O_WRONLY);
	if (-1 == fd)
	{
		perror("fail open fifo");
		return -1;
	}
	
	while (1)
	{
		write(fd, "hello world", 11);
		sleep(1);
	}
	
	close(fd);

	return 0;
}

阻塞IO(Blocking IO)是一种传统的IO操作模式,在这种模式下,当一个IO操作(如读、写)执行时,如果不能立即完成,程序会暂停执行,直到该IO操作完成。这种IO模式具有以下几个特点:

1. 同步性

阻塞IO是同步的,意味着应用程序必须等待IO操作完成才能继续执行后续操作。在执行IO操作时,调用线程会被阻塞,无法继续处理其他任务。

2. 线程阻塞


当IO操作不能立即完成时,调用该操作的线程会被挂起,直到IO操作完成。这会导致线程在IO等待期间无法执行其他任务,从而降低CPU的利用率。

3. 编程模型简单


阻塞IO的编程模型相对简单,易于理解和实现。它不需要复杂的轮询或回调机制,直接通过系统调用来完成IO操作。

4. 适用场景


阻塞IO适用于连接数较少且每个连接需要较长时间处理的场景。在这种场景下,由于连接数不多,线程阻塞对整体性能的影响较小。
阻塞IO也适用于对并发性能要求不高的场景,如简单的文件读写操作或小型网络应用。

5. 缺点


在高并发场景下,阻塞IO的效率较低。因为每个连接都需要一个独立的线程来处理,当连接数增多时,会消耗大量的线程资源,可能导致线程资源耗尽。
线程在等待IO操作完成时处于阻塞状态,无法充分利用CPU资源,降低了系统的整体性能。

6. 改进方式


为了解决阻塞IO在高并发场景下的性能问题,可以采用非阻塞IO(Non-blocking IO)或IO多路复用(IO Multiplexing)等技术。非阻塞IO允许程序在等待IO操作完成时继续执行其他任务,而IO多路复用则允许一个线程同时处理多个IO操作。

综上所述,阻塞IO是一种简单但效率较低的IO操作模式,适用于连接数较少且对并发性能要求不高的场景。在高并发场景下,为了提高性能和资源利用率,可以考虑采用非阻塞IO或IO多路复用等更高效的IO操作模式。

2.非阻塞IO

非阻塞IO(Non-Blocking IO)是一种IO操作模式,其特点如下:

非阻塞特性:程序在发起IO请求后,不会等待IO操作完成,而是立即返回,程序可以继续执行后续操作。这提高了程序的运行效率和响应速度。
同步性:虽然非阻塞IO在发起请求后不会阻塞程序,但它是同步的,因为程序需要定期检查IO操作是否完成。这通常通过轮询或事件通知机制来实现。
适用场景:非阻塞IO适用于需要同时处理多个IO操作的并发环境,以及对IO操作响应时间要求较高的场景。
实现方式:非阻塞IO的实现通常依赖于操作系统的支持,例如通过设置socket为非阻塞模式,或使用特定的系统调用(如select、poll、epoll等)来检查IO操作的就绪状态。

总结来说,非阻塞IO允许程序在等待IO操作完成时继续执行其他任务,提高了程序的并发处理能力和响应速度但CPU占用率高

实现:

1.获取原文件描述属性

2.增加非阻塞属性

3.设置属性

非阻塞read.c

#include "head.h"


int main(int argc, const char *argv[])
{
	char buff[1024] = {0};
	mkfifo("./myfifo", 0664);
	
	int fifofd = open("./myfifo", O_RDONLY);
	if (-1 == fifofd)
	{
		perror("fail open fifo");
		return -1;
	}
	//1. 获取文件原有属性	
	int flag = fcntl(0, F_GETFL);
	//增加非阻塞属性
	//flag = flag | O_NONBLOCK;
	//去掉非阻塞属性
	flag = flag & (~O_NONBLOCK);
	//设置属性
	fcntl(0, F_SETFL, flag);

	while (1)
	{
		memset(buff, 0, sizeof(buff));
		fgets(buff, sizeof(buff), stdin);
		printf("STDIN : %s\n", buff);

		memset(buff, 0, sizeof(buff));
		read(fifofd, buff, sizeof(buff));
		printf("FIFO : %s\n", buff);
	}
	
	close(fifofd);

	return 0;
}

非阻塞write.c

#include "head.h"


int main(int argc, const char *argv[])
{	
	mkfifo("./myfifo", 0664);
	
	int fd = open("./myfifo", O_WRONLY);
	if (-1 == fd)
	{
		perror("fail open fifo");
		return -1;
	}
	
	while (1)
	{
		write(fd, "hello world", 11);
		sleep(1);
	}
	
	close(fd);

	return 0;
}

3.信号驱动IO

信号驱动IO(Signal-driven IO)是一种异步IO机制,其特点如下:

异步通知:当IO操作准备就绪时,内核通过发送信号(如SIGIO)来通知应用程序。这样,应用程序可以在数据准备好时立即处理,而无需持续轮询或阻塞等待,节省CPU
注册信号处理函数:应用程序需要预先注册一个信号处理函数,用于在接收到SIGIO信号时执行相应的IO操作。
底层驱动支持:信号驱动IO的实现需要底层驱动的支持,驱动在IO操作准备就绪时负责发送SIGIO信号。
适用场景:信号驱动IO特别适用于需要处理大量并发连接且对IO响应时间要求较高的场景,如网络服务器等。

总结来说,信号驱动IO通过信号机制实现异步IO操作,提高了程序的响应速度和并发处理能力。

实现:


1.增加异步属性

2.并联信号和当前进程

3.注册信号

4.信号调用函数

信号驱动read.c

#include "head.h"


void handle(int signo)
{
	char buff[1024] = {0};
	fgets(buff, sizeof(buff), stdin);
	printf("STDIN : %s\n", buff);
}
int main(int argc, const char *argv[])
{
	signal(SIGIO, handle);
	char buff[1024] = {0};
	mkfifo("./myfifo", 0664);
	
	int fifofd = open("./myfifo", O_RDONLY);
	if (-1 == fifofd)
	{
		perror("fail open fifo");
		return -1;
	}
	//1. 获取文件原有属性	
	int flag = fcntl(0, F_GETFL);
	flag = flag | O_ASYNC;
	fcntl(0, F_SETFL, flag);
		
	//2.关联当前进程
	fcntl(0, F_SETOWN, getpid());


	while (1)
	{

		memset(buff, 0, sizeof(buff));
		read(fifofd, buff, sizeof(buff));
		printf("FIFO : %s\n", buff);
	}
	
	close(fifofd);

	return 0;
}

信号驱动write.c

#include "head.h"


int main(int argc, const char *argv[])
{	
	mkfifo("./myfifo", 0664);
	
	int fd = open("./myfifo", O_WRONLY);
	if (-1 == fd)
	{
		perror("fail open fifo");
		return -1;
	}
	
	while (1)
	{
		write(fd, "hello world", 11);
		sleep(1);
	}
	
	close(fd);

	return 0;
}

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

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

相关文章

IO进程day03(获取文件属性、目录操作、库Lib)

目录 【1】获取文件属性 1》stat函数 2》获取文件类型 3》获取文件权限 练习:编程实现“ls -l 文件名” 的功能 4》stat、fstat、lstat的区别 【2】目录操作 【3】库 Lib 1》文件分类 1> 头文件: 以 .h结尾的文件 2> 源文件&#xff1a…

Qt之控件介绍

目录 控件概述 QWidget核心属性 1.enabled属性 2.geometry属性 3.windowTitle属性 4.windowIcon属性 5.windowOpacity属性 6.cursor属性 7.font属性 8.toolTip属性 9.focusPolicy属性 10.styleSheet属性 按钮类控件: 1.PushButton 2.RadioBu…

Leetcode 17. 电话号码的字母组合 C++实现

Leetcode 17. 电话号码的字母组合 问题:给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。 算法:递归嵌…

PyTorch深度学习模型训练流程:(二、回归)

回归的流程与分类基本一致,只需要把评估指标改动一下就行。回归输出的是损失曲线、R^2曲线、训练集预测值与真实值折线图、测试集预测值散点图与真实值折线图。输出效果如下: 注意:预测值与真实值图像处理为按真实值排序,图中呈现…

机器学习概述与应用:深度学习、人工智能与经典学习方法

引言 机器学习(Machine Learning)是人工智能(AI)领域中最为核心的分支之一,其主要目的是通过数据学习和构建模型,帮助计算机系统自动完成特定任务。随着深度学习(Deep Learning)的崛起,机器学习技术在各行各业中的应用变得越来越广泛。在本文中,我们将详细介绍机器学…

Datawhale X 李宏毅苹果书 AI夏令营 Task1笔记

课程内容 学习笔记 (一)术语解释 一 . 机器学习(Machine Learning,ML) 机器学习,在本书的解释中是让机器具备找一个函数的能力。个人理解是基于所拥有的数据构建起概率统计模型来对数据进行预测与分析。…

python可视化-散点图

散点图可以了解数据之间的各种相关性,如正比、反比、无相关、线性、指数级、 U形等,而且也可以通过数据点的密度(辅助拟合趋势线)来确定相关性的强度。另外,也可以探索出异常值(在远超出一般聚集区域的数据…

【Java】Record的使用 (简洁教程)

Java系列文章目录 补充内容 Windows通过SSH连接Linux 第一章 Linux基本命令的学习与Linux历史 文章目录 Java系列文章目录一、前言二、学习内容:三、问题描述四、解决方案:4.1 为什么引入Record4.2 Record与Class区别4.3 使用场景 五、总结:…

使用uni-app开发微信小程序

一、前提环境 1.1 :uniapp开发文档:https://uniapp.dcloud.net.cn/quickstart-cli.html 细节都在这一页,这里不过多解释 二、开发工具下载 2.1 微信开发者工具 下载链接:https://developers.weixin.qq.com/miniprogram/dev/dev…

Java:Calendar类

文章目录 Calendar类常用方法代码 黑马学习笔记 Calendar类 calendar是可变对象,一旦修改后其对象本身表示的时间将发生变化 原始对象会跟着修改,造成原始对象的丢失 常用方法 代码 package Time;import java.util.Calendar; import java.util.Date;/…

【RabbitMQ高级特性】消息可靠性原理

1. 消息确认机制 1.1 介绍 我们可以看到RabbitMQ的消息流转图: 当消息从Broker投递给消费者的时候会存在以下两种情况: consumer消费消息成功consumer消费消息异常 如果说RabbitMQ在每次将消息投递给消费者的时候就将消息从Broker中删除&#xff0c…

用 like concat 不用 like,为了防止sql注入;#{}和${}的区别和用法;#{}预防SQL注入的原理

一、like concat 和 like mybatis中为了防止sql注入&#xff0c;使用like语句时并不是直接使用&#xff0c;而是使用concat函数<if test"goodName ! null and goodName ! "> and good_name like concat(%, #{goodName}, %)</if> concat()函数1、功能&a…

Webbench1.5安装使用Ubuntu

1、安装依赖包 sudo apt-get update sudo apt-get install libtirpc-dev2、安装Webbench1.5 参考https://github.com/baiguo/webbench-1.5 # 可能需要root权限&#xff0c;我是切换到root用户才安装成功 wget http://home.tiscali.cz/~cz210552/distfiles/webbench-1.5.tar.…

APP.vue引入子组件进行页面展示

一.将vue项目启动服务器原始页面进行清空 打开APP.vue文件&#xff0c;将<template>标签里的内容和<style>标签里的内容 ctrl/ 选中进行注释&#xff0c;以及引入的Helloworld.vue文件内容代码进行注释 并且 ctrls 保存 服务器页面从原始页面 变为空白 二.在comp…

树莓派4B安装golang最新版(20210520)

前置条件&#xff1a; 树莓派4B 安装官方系统 Linux raspberrypi 5.10.17-v7l #1414 更换最新版的原因&#xff1a; 截至 2021.5.20 &#xff0c;Raspberry Pi OS 最新版系统中&#xff0c;默认安装golang1.11&#xff0c;但是使用 go get golang.org/x/crypto/ssh 时&#xff…

推荐系统实战(七)-多任务多场景(上)多任务

多任务Multi-Task&#xff0c;有时也被称为多目标Multi-Objective建模。比如说电商场景下&#xff0c;希望曝光的物料被多多点击&#xff0c;还希望商品被下单购买&#xff0c;因此同时建模三个目标&#xff1a;曝光到点击CTR&#xff0c;点击到购买转换率CVR&#xff0c;曝光到…

记一次对某佛教系统的漏洞挖掘

前言 简单记录一次漏洞挖掘&#xff0c;一个系统居然爆了这么多类型的洞&#xff0c;于是想记录哈。(比较基础&#xff0c;我是菜狗&#xff0c;大佬轻喷) 业务介绍 是一个某佛教的系统 有一些佛教的学习资源、一些佛教相关的实物商品可购买&#xff0c;有个人中心&#xff…

PyCharm中python语法要求——消去提示波浪线

PyCharm中python语法要求——消去提示波浪线 关闭代码规范检查 在Setting里边搜索pep&#xff0c;取消勾选pep8 coding style violation 问题产生 解决问题 按照下图操作&#xff0c;也可直接CtrlAlts弹出设置页面 在 Settings 中 &#xff1a; Editor > Color Sheame >…

设计模式26-解析器模式

设计模式26-解析器模式 动机定义与结构定义结构 C代码推导代码说明 优缺点应用总结 动机 在软件构建过程中&#xff0c;如果某一特定领域的问题比较复杂&#xff0c;类似结构会不断重复的出现。如果使用普通的编程方式来实现&#xff0c;将面临非常频繁的变化。 在这种情况下&…

二叉树算法算法【二叉树的创建、插入、删除、查找】

一、原理 1.1、二叉排序树的插入 1.2、二叉树的删除 &#xff08;1&#xff09;删除度为0的节点&#xff0c;就是最后的叶子节点&#xff0c;直接删除就可以了. &#xff08;2&#xff09;删除度为1的节点&#xff0c;就是爷爷节点接收孙子节点。 &#xff08;3&#xff09;删…