热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

网络编程的初印象

现在的软件,单机模型的越来越少了,更多的是CS模型,这个模型之间的通信一般是通过socket技术来实现。而socket又涉及到TCPIP协

现在的软件,单机模型的越来越少了,更多的是C/S模型,这个模型之间的通信一般是通过socket技术来实现。而socket又涉及到TCP/IP协议,这也就是今天我们主题,基于TCP/IP协议的网络编程。

对于TCP/IP协议的理论学习,这里推荐的是Richard 的 《TCP/IP 详解卷1:协议》和《UNIX 网络编程卷1:套接口 API》(俗称 UNP1)。

我们先看一个场景问题:一个server如何应对成百上千个client。

一个最简单的模型就是用一个进程来处理所有的client连接。但是回头想想,在处理过程中,如果有上百个连接同时请求服务,下一个连接首先要等待上一个连接处理完(同步)。这个在处理上的连接很有可能阻塞在数据操作(I/O)上,这样处理连接的效率之差及client响应之慢是几乎是所有人不能接受的。

为了提高效率,我们做一点改进,对每一个client连接产生一个线程(windows)或一个进程(linux)来处理,如果忽略线程或进程的上下文切换损耗,就单单看产生的成百上千个线程和进程的可行性,对不起,操作系统是有线程或进程的资源上限。

为了解决线程资源频繁切换造成的资源损耗和资源数限制问题,我们再给予改进。我们采用一个线程池来处理部分连接,其他连接排队等候。那么问题又来了,因为一个机器的CPU不多,同时能处理的也就那么几个连接,响应效率和处理效率依然提不上去。

其实网络耗时一般都是在数据操作(I/O)上,一个输入操作通常包括两个不同的阶段:

  • 等待数据准备好;
  • 从内核向进程复制数据;

对于一个套接字上的输入操作,第一步通常涉及等待数据从网络中到达。当所等待分组到达时,它被复制到内核中的某个缓冲区。第二步就是把数据从内核缓冲区复制到应用进程缓冲区。

很幸运的是,我们出生在这个时代,这些网络编程的效率问题,计算机前辈们已经帮我们想好了。就是我们网络编程里经典的Reactor(又称异步阻塞IO、IO多路复用) 和 Proactor(又称异步非阻塞IO) 两种并发编程模式。他们都是基于事件驱动的,我们就是把网络中需要处理的事件注册到事件管理器中(比如网络行为事件,IO 操作事件…..),然后等事件状态就绪了,它就用回调的方式通知我们去处理。这样的话,只用一个线程就可以处理几乎所有的事件,而且CPU也不会闲着。

现在来简单介绍一下Unix下服务器端常用的5种I/O模型:

  • 同步阻塞式I/O;
  • 同步非阻塞式I/O;
  • I/O多路复用;
  • 信号驱动式I/O;
  • 异步I/O;

1、  同步阻塞式I/O

默认情况下,所有套接字都是阻塞的,以数据报套接字作为例子,如图:

用户空间下的应用进程调用recvform,其中系统调用直到内核的数据报到达且被复制到应用进程的缓冲区中或者发生错误才返回。最常见有错误是系统调用被信号中断。我们说的进程从调用recvfrom开始到它返回的整段时间内是被阻塞的。recvfrom成功返回后,应用进程开始处理数据报。

2、  同步非阻塞式I/O

当把一个套接字设置成非阻塞,是在通知内核:当所请求的I/O操作非得把本进程投入睡眠才能完成时,不要把本进程投入睡眠,而是返回一个错误。我们来看一个例子:

前三次调用recvfrom时,没有数据可返回,因此内核转而立即返回一个EWOULDBLOCK错误。第四次调用recvfrom时已有一个数据报准备好,它被复制到应用进程缓冲区,于是recvfrom成功返回,用户空间应用进程继续处理。

当一个应用程序像这样对一个非阻塞描述符循环调用recvfrom时,我们称之为轮询(polling)。应用进程持续轮询内核,以查看某个操作是否就绪。这么做往往耗费大量CPU时间。

3、  I/O多路复用

有了I/O复用,我们就可以调用select或poll,阻塞在这两个系统调用的某一个之上,而不是阻塞在真正的I/O系统调用上,如图:

我们阻塞于select调用,等待数据报套接字变为可读。当select返回套接字可读这一条件时,我们调用recvfrom把所读数据报复制到应用进程缓冲区中。使用select的优势在于我们可以等待多个描述符就绪。

4、  信号驱动式I/O

我们也可以使用信号,让内核在描述符就绪时发送SIGIO信号通知我们,如图:

我们首先开启套接字的信号驱动式I/O功能,并通过sigaction系统调用安装一个信息处理函数。该系统调用立即返回,我们的进程继续工作,也就是他没有被阻塞。当数据报准备好读取时,内核就为该进程产生一个SIGNO信号。随后即可以在信号处理函数中调用recvfrom函数读取数据报,又通知主循环已准备好待处理,也可以立即通知主循环,让它读取数据报。

这种模型的优势在于等待数据报到达期间进程不被阻塞。主循环可以继续执行,只要等待来处信号处理函数的通知:既可以是数据已准备好被处理,也可以是数据报已准备好被读取。

5、  异步I/O

异步I/O的工作机制是:告知内核启动某个操作,并让内核在整个操作(包括将数据从内核复制到我们自己的缓冲区)完成后通知我们。这种模型与信号驱动模型的主要区别在于:信号驱动式I/O是由内核通知我们何时可以启动一个I/O操作,而异步I/O模型是由内核通知我们I/O操作何时完成。如图所示:

我们调用aio_read函数,给内核传递描述符、缓冲区指针、缓冲区大小和文件偏移,并告诉内核当整个操作完成时如何通知我们。该系统调用立即返回,而且在等待I/O完成期间,我们进程不被阻塞。该例子要求内核在操作完成时产生某个信号,该信号直到数据已复制到应用进程缓冲区才产生,这一点不同于信号驱动式I/O模型。

可以看出,前4种模型的主要区别在于第一阶段,因为它们的第二阶段是一样的:在数据从内核复制到调用者的缓冲区期间,进程阻塞于recvfrom调用。相反异步I/O模型在这两个阶段都要处理,从而不同于其他4种模型。以下表格是5种模型的比较:

备注:

同步与异步,描述的是用户线程与内核的交互方式

同步:用户线程发起IO请求后需要等待或者轮询内核IO操作完成后才能继续执行;

异步:用户线程发起IO请求后仍继续执行,当内核IO操作完成后会通知用户线程,或者调用用户线程注册的回调函数。

阻塞与非阻塞,描述的是用户线程调用内核IO操作的方式

阻塞:IO操作需要彻底完成后才返回到用户空间;

非阻塞:IO操作被调用后立即返回给用户一个状态值,无需等到IO操作彻底完成。

线程池:在还没有任务到来之前,创建一定数量的线程,放入空闲队列中。这些线程都是处于睡眠状态,不消耗CPU,而只是占用较小的内存空间。当请求到来之后,缓冲池给这次请求分配一个空闲线程,把请求传入此线程中运行,进行处理。当预先创建的线程都处于运行状态,即预制的线程不够用,线程池可以自由创建一定数量的新线程,用于处理更多的请求。当系统比较闲的时候,也可以通过移除一部分一直处于停用状态的线程。

转:https://www.cnblogs.com/iyoyos/p/4235470.html



推荐阅读
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 李逍遥寻找仙药的迷阵之旅
    本文讲述了少年李逍遥为了救治婶婶的病情,前往仙灵岛寻找仙药的故事。他需要穿越一个由M×N个方格组成的迷阵,有些方格内有怪物,有些方格是安全的。李逍遥需要避开有怪物的方格,并经过最少的方格,找到仙药。在寻找的过程中,他还会遇到神秘人物。本文提供了一个迷阵样例及李逍遥找到仙药的路线。 ... [详细]
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • 本文介绍了九度OnlineJudge中的1002题目“Grading”的解决方法。该题目要求设计一个公平的评分过程,将每个考题分配给3个独立的专家,如果他们的评分不一致,则需要请一位裁判做出最终决定。文章详细描述了评分规则,并给出了解决该问题的程序。 ... [详细]
  • 原文地址:https:www.cnblogs.combaoyipSpringBoot_YML.html1.在springboot中,有两种配置文件,一种 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 【shell】网络处理:判断IP是否在网段、两个ip是否同网段、IP地址范围、网段包含关系
    本文介绍了使用shell脚本判断IP是否在同一网段、判断IP地址是否在某个范围内、计算IP地址范围、判断网段之间的包含关系的方法和原理。通过对IP和掩码进行与计算,可以判断两个IP是否在同一网段。同时,还提供了一段用于验证IP地址的正则表达式和判断特殊IP地址的方法。 ... [详细]
  • Nginx使用AWStats日志分析的步骤及注意事项
    本文介绍了在Centos7操作系统上使用Nginx和AWStats进行日志分析的步骤和注意事项。通过AWStats可以统计网站的访问量、IP地址、操作系统、浏览器等信息,并提供精确到每月、每日、每小时的数据。在部署AWStats之前需要确认服务器上已经安装了Perl环境,并进行DNS解析。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
author-avatar
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有