网络模型

套接字socket通信属于网络的传输层通信,通常都是由操作系统实现,主要有两种tcp和udp两种(分别实现的tcp协议和udp协议),本文诉述的网络模型都是建立在Linux操作系统实现的套接字API基础上。(套接字实现进程之间的通信)

一 、Linux 5种 I/O模型

网络数据I/O 操作拥有两个阶段,以读数据操作为例:1 操作系统读取网络数据成功放入系统内核缓冲区(或者说tcp/udp缓冲区,因为操作系统这网络模型中实现是传输层协议), 2 系统内核缓冲区数据被拷贝到应用程序缓冲区(即通常我们的应用程序中定义的数据空间)

如果已经了解常见的网络套接字编程函数,可跳过1.1-1.5

1.1阻塞I/O

应用程序调用阻塞的I/O函数(recv()/recvfrom()),进程会一直阻塞,直到数据拷贝到用户缓冲区成功。

代码示例1 (完整代码示例见附录1): 实现发送数据到服务端,并读取服务端的返回数据

{

/* 从标准输入设备取得字符串*/

len =read(STDIN_FILENO,buffer,sizeof(buffer));

/* 将字符串传送给server端*/

sendto(s,buffer,len,0,(struct sockaddr *)&addr,addr_len);

/* 接收server端返回的字符串*/

len = recvfrom(s,buffer,sizeof(buffer),0,(struct sockaddr *)&addr,&addr_len);

printf("receive: %s",buffer);

}

以recvfrom 函数为例,当应用程序调用此函数时,应用程序会进入内核态,等待数据准备完成(此过程 应该是操作系统读取tcp/udp 数据包过程,先读取固定大小的tcp报文头部,然后根据头部指定的包体大小读取完整tcp报文), 数据准备完成后,由操作系统负责将数据拷贝到用户应用程序的缓冲区(即 程序中定义的buffer缓冲区),并切换到用户态。

(用户态 :可简单理解为运行用户的代码例如上面的示例代码  内核态:是操作系统,运行自己的代码)

1.2非阻塞I/O

与阻塞I/O模型不同,非阻塞I/O 需要设置套接字(示例代码中 变量s 为非阻塞模式 fcntl(s, F_SETFL, O_NONBLOCK)), 在调用 recvfrom 函数后,内核判断无数据准备好(内核缓冲区即tcp/udp缓冲区未读取到完整tcp报文),则直接切换到用户态,并返回EWOULDBLOCK,如图6.2 中,此种模型需要应用程序不断调用recvfrom函数直到成功读取数据,在内核态与用户态之间的不断切换会消耗cpu时间。

1.3 I/O复用(select + epoll)

select 函数原型:

int select(int nfds, fd_set *readset, fd_set *writeset,fd_set* exceptset, struct tim *timeout);

此函数的最后一个参数timeout 决定了select系统调用是否阻塞或者阻塞多久。

1. timeout=NULL(阻塞:直到有一个fd位被置为1函数才返回) 类似 1.1 recvfrom阻塞

2. timeout所指向的结构设为非零时间(等待固定时间:有一个fd位被置为1或者时间耗尽,函数均返回)

3. timeout所指向的结构,时间设为0(非阻塞:函数检查完每个fd后立即返回)

注意select系统调用的阻塞与其监控的套接字(readset writeset集合中套接字)阻塞性质无关,由参数timeout决定,另外select函数在内核态,只判断有无数据准备好(即网络数据tcp/udp包是否到达系统tcp/udp缓存区), 无1.1 中介绍的函数返回时将数据从系统缓存区拷贝到用户缓冲区过程。

(对于网上很多地方 评论select函数是阻塞的 是不全面的)

在select 函数成功返回(>0) 表时某些套接字可读时,再使用recvfrom函数读取套接字上面的数据(如1.1,1.2 描述,通常这里会将套接字设置成阻塞模式,调用recvfrom函数)

代码实例:

while(1)

{

FD_ZERO(&fds); //每次循环都要清空集合,否则不能检测描述符变化

/*

select函数 每次返回会清除 参数readset

和 wrietset中没有准备好的套接字,所以每次轮询都需要重新添加监控集合中

*/

FD_SET(sock,&fds); //添加描述符

FD_SET(fp,&fds); //同上

maxfdp=sock>fp?sock+1:fp+1;    //描述符最大值加1

switch(select(maxfdp,&fds,&fds,NULL,&timeout))   //select使用

{

case -1: exit(-1);break; //select错误,退出程序

case 0:break; // 没有数据准备好

default:

if(FD_ISSET(sock,&fds)) //测试sock是否可读,即是否网络上有数据

{

/*由于套接字sock上面数据已经准备好,

这里会将数据从内核缓冲区拷贝到用户缓冲区buffer*

*/

recvfrom(sock,buffer,256,.....);

}// end if break;

}// end switch

}//end while

}//end main

缺点:

1 数据需要由应用程序在得知数据准备好后,重新切换到内核态,拷贝数据到用户态缓冲区

2 需要循环遍历寻找具体是哪些描述符上数据准备就绪

注意 linux 2.6 版本后epoll_wait采用了mmap(mmap 内存映射 简单说就是将文件或者对象映射到一块内存上,方便多个进程之间共享和直接操作,无需通常读取文件时的先内核态读取,再拷贝用户态缓冲区过程),这样当epoll_wait 在网络数据准备就绪后返回时,其内核态数据已经拷贝到用户缓冲区。

epoll 主要解决了select模型的两个缺点(具体见1.3节),尤其是第二个缺点,在有大量并发连接,且只有少数活跃的情况下的效率问题。

epoll 使用主要有以下三个函数:

 1、int epoll_create(int size)

创建一个epoll句柄,参数size用来告诉内核监听的数目。

/* event 包含了需要监听的时间以及用来保存数据的用户缓冲区*/

2、int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)

epoll事件注册函数,(epfd 是函数1 返回的epoll句柄)

/* epoll_wait函数返回时,events集合中包含了准备就绪的套接字以及数据)*/

3、 int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout)

等待事件的产生,类似于select()调用。参数events用来从内核得到事件的集合,timeout(0 非阻塞 -1 阻塞)

和select不同 epoll_wait 返回时,events集合中已经包括了就绪事件以及对应的数据。换句话说 epoll_wait在返回时 已经完成数据从内核缓冲区拷贝到用户缓冲区工作(由于epoll_wait返回时已经知道哪些套接字上数据准备就绪,无需select返回后 仍需轮询确认哪些套接字上准备就绪,同时也无需再调用函数recvfrom复制数据到用户缓冲区)。

1.4信号渠道I/O(SIGIO)

1 首先设置套接字可进行套接字信号驱动I/O(ioctl) 和设置套接字非阻塞性质类似。

2 通过系统调用(sigaction),指定信号处理程序(通常会让主程序睡眠等待并接受信号处理)

3 信号到达时,当前进程会被中断或者由睡眠状态唤醒然后调用信号处理函数(该信号处理函数通常可以直接处理网络数据或者通过其他状态位通知主程序数据已经准备好)

1.5异步I/O

异步I/O 是linux 2.6 新增的一个特性。aio_read 函数和(epoll类似)会传递给内核一个用户缓冲区,内核会在数据准备就绪后将数据复制到用户缓冲区中后 发送SIGIO信号给当前进程,或者调用aio_read函数调用中指定的回调函数。

这里和之前(1.1-1.4)显然不同,aio_read函数调用后,会立即返回,后续无需轮询查询网络数据是否准备就绪,在网络数据准备就绪后(且已拷贝到用户缓冲区)时,会自动调用之前调用aio_read函数时指定的回调函数地址或者发送信号给当前进程(当前进程会被中断进入信号处理进程)。

二 、阻塞,非阻塞,同步,异步概念总结

通过对1.1,1.2,1.3 的理解可以归纳阻塞和非阻塞是系统在调用系统调用(recvfrom,select)的时候函数的实现方式而已。

阻塞:调用某个函数(recvfrom select[timeout=NULL])  由于数据未准备好或者其他原因,当前进程会挂起进入睡眠

非阻塞:调用某个函数(recvfrom select[timeout=NULL]) 由于数据未准备好或者其他原因,当前进程并不进入睡眠,而是立即返回一个状态反应此种情况给用户程序

非阻塞缺点:通常需要用户轮询调用某个函数直到读取到数据,导致用户态和系统态之间的来回切换,消耗cpu资源,

阻塞缺点:函数不能立即返回,用户进程进入睡眠状态,无法处理其他事情(内核态轮询数据是否准备就绪)

通过对1.3,1.4,1.5 可以归纳同步和异步是相对于用户程序和操作系统内核的交互方式而言的.

同步: 应用程序轮询查看是否准备就绪 (用户态切换内核态 轮询)

异步:内核在IO事件发生的时候通知应用程序(信号或者回调函数)。

同步和阻塞区别: 同步是用户态程序 轮询调用系统调用(select epoll_wait)查看数据是否准备就绪,阻塞是用户程序调用一个系统调用(recvfrom)后,切换到内核态,在内核态中不断轮询查询数据是否准备就绪。

由于同步 是由用户态不断切换到内核态的轮询,因此证明了网上的说法同步是可以被用户信号中断的。(内核态不能接受用户信号)

异步和同步的区别:异步没有类似同步(select, epoll_wait)那样的应用程序轮询调用某个系统调用,而是在数据准备好,发送信号给当前进程或者开启新线程调用回调函数。(对于网上有人将epoll模型归纳为也异步,其理由是在用户进程得到数据就绪通知的同时,数据已经拷贝到用户缓冲区,此种说法不妥)

异步和非阻塞区别:两者并无直接关联。

综述:阻塞和非阻塞是某个函数内部的实现方式,同步和异步在网络模型是描述用户程序和操作系统之间的交互方式的。同步模型(select epoll)中可以有非阻塞的函数调用,也可以有阻塞函数调用(因此有人将I/O复用模型归纳为同步阻塞模型,也是合理的,因为select和recvfrom在这个I/O模型里选择了阻塞调用方式),异步I/O模型 在用户态和系统态都没有轮询操作,而是在网络数据准就绪后通过异步的方式处理(开启线程调用回调函数或者发送信号给当前进程)。

通过以上分析: 信号渠道I/O 可以归纳为 异步阻塞模型(网络有类似归纳方法) (设置完SIGIO信号处理程序后,无需用户进程轮询 这是异步的概念,数据到达就绪后,信号处理程序中在阻塞套接字上调用recvfrom函数读取实际数据,阻塞概念)

Select和epoll 可以归为同步阻塞 同步:因为都需要用户进程轮询(select epoll_wait)  阻塞:因为select epoll_wait 在这个I/O模型中通常都是设置一定的阻塞时间,且在select调用之后,会阻塞调用recvfrom或者write等函数。

三 、附录

网址

http://wiki.babel.baidu.com/twiki/bin/view/Ps/Ns/AsynchronousAndSimultaneous (垃圾)

http://www.cnblogs.com/kunhu/p/3624000.html

http://www.cnblogs.com/renxs/p/3683189.html

http://www.cnblogs.com/pigerhan/p/3474217.html (proactor 和 reactor模式)

http://blog.chinaunix.net/uid-14874549-id-3487338.html

http://blog.chinaunix.net/uid-26669729-id-3077015.html

http://blog.csdn.net/yangzhiloveyou/article/details/9156405 (信号I/O)

书籍推荐

unix 环境高级编程

windows 网络编程 (第八章讲解了windows下的5种网络模型)

unix网络编程 (两卷)

tcp/ip 详解卷1

ACE中间件 (封装了window和linux 下的网络函数的开源网络编程工具包,同时提供其他例如日志,线程池等功能,对设计模式运用很全面,上下两本)

4.1 Linux下阻塞套接字使用示例

4.2 Linux信号I/O模型

http://blog.csdn.net/yangzhiloveyou/article/details/9156405

注意sigsupend 函数会实得当前函数进入睡眠,同时可接受信号

4.3 Linux AIO 异步I/O模型

http://blog.chinaunix.net/uid-52437-id-2108857.html

时间: 2024-08-09 23:52:44

网络模型的相关文章

barabasilab-networkScience学习笔记3-随机网络模型

第一次接触复杂性科学是在一本叫think complexity的书上,Allen博士很好的讲述了数据结构与复杂性科学,barabasi是一个知名的复杂性网络科学家,barabasilab则是他所主导的一个实验室,这里的笔记则是关于里面介绍的课程的slider的笔记,当然别人的课程不是公开课,所以从ppt里只能看到骨干的东西了,对了补充下,slider相关的书籍在这里可以找到 说实话这一节的slider我没有看很明白公式,数学功底差了,如果你能够有更好的解释欢迎留言 Random Networks

Caffe学习系列——工具篇:神经网络模型结构可视化

Caffe学习系列--工具篇:神经网络模型结构可视化 在Caffe中,目前有两种可视化prototxt格式网络结构的方法: 使用Netscope在线可视化 使用Caffe提供的draw_net.py 本文将就这两种方法加以介绍 1. Netscope:支持Caffe的神经网络结构在线可视化工具 Netscope是个支持prototxt格式描述的神经网络结构的在线可视工具,网址:  http://ethereon.github.io/netscope/quickstart.html  它可以用来可

openstack安装配置—— 实例启动(双网络模型)

    启动实例前至少需要配置好nova和neutron服务,当然实际中cinder服务也是必须的,否则一台虚拟是可以启动,但没有数据卷也是不合常理的.启动实例之前需要事先创建好网络模型,私有网络模型是包含公有网络模型的,所以我们前面配置netron服务时直接选择了私有网络模型,当然此时我们要想启动实例,公有网络模型和私有网络模型我们都可以选择,本实验中我们会先带大家在公有网络模型下启动一个实例,私有网络模型下启动实例要比公有网络下复杂一些. 第一步:创建物理网络 [[email protect

Kubernetes网络模型概念

Kubernetes网络模型 Kubernetes网络模型设计的一个基础原则是:每个Pod都拥有一个独立的IP地址,而且假定所有Pod都在一个可以直接连通的.扁平的网络空间中.所以不管它们是否运行在同一个Node(宿主机)中,都要求它们可以直接通过对方的IP进行访问.设计这个原则的原因是,用户不需额外考虑如何建立Pod之间的连接,也不需要考虑将容器端口映射到主机端口等问题. 实际在Kubernetes的世界里,IP是以Pod为单位进行分配的. 按照这个网络抽象原则,Kubernetes对网络有什

知识网络模型:记忆是一个整合的过程

?记忆的重要性 ?网状图(地图)模型 ?"整合"才是记忆之道 ?"活记"和"死记" 声明:这里所讲的记忆,主要是在学习领域.  前言:很难给这篇文章起个比较好的标题,一开始起的是"记忆之道:摆脱死记硬背",但是感觉这篇文章重点不在于讲记忆的各种技巧:想要用"记忆的本质",但是一谈到本质,就是比较深刻的问题,而记忆,本质可能更多在于生物和神经领域.最后,就用 "知识网络模型:记忆是一个整合的过程&q

队列理论和队列网络模型 queueing theory and queueing network model

(学了大半个月,赶紧把脑袋里装的东西倒一点点出来,不然就忘记了.看别人的PPT都是顺理成章.一气呵成,看我能讲出多少东西) 1队列理论 队列在生活中随处可见,例如排队买票,排队打饭,排队做地铁等等.那将诸如此类的队列抽象一下,可归纳为一下3要术:排队能容纳的总人数(例如食堂空间只有那么大,最长的队伍只能容纳20人).服务率(例如食堂阿姨打菜的速度).等待时间.   我们通过数学公式以及生活常识可得到如下关系:排队总人数=服务率乘以等待时间. 将队列理论应用于服务器处理的排队,那么排队的要素增加一

【程序猿笔试面试复习】之中的一个 网络与通信篇(一) 几大网络模型:OSI、TCP/IP、B/S与C/S、MVC结构

9.1网络模型 9.1.1. OSI七层模型 OSI(Open System Interconnection,开放系统互联)七层网络模型称为开放式网络互联參考模型.其为国际标准组织指定的一个指导信息互联.互通和协作的网络规范. 开放是指仅仅要遵循OSI标准,位于世界上不论什么地方的不论什么系统之间都能够进行通信,开放系统是指遵循互联协议的实际系统,如电话系统. 从逻辑上能够将OSI开放系统互联分为七层模型,由下至上分别为物理层.数据链路层.网络层.传输层.会话层.表示层和应用层. 当中.上三层称

TensorFlow学习笔记(8)--网络模型的保存和读取【转】

转自:http://blog.csdn.net/lwplwf/article/details/62419087 之前的笔记里实现了softmax回归分类.简单的含有一个隐层的神经网络.卷积神经网络等等,但是这些代码在训练完成之后就直接退出了,并没有将训练得到的模型保存下来方便下次直接使用.为了让训练结果可以复用,需要将训练好的神经网络模型持久化,这就是这篇笔记里要写的东西. TensorFlow提供了一个非常简单的API,即tf.train.Saver类来保存和还原一个神经网络模型. 下面代码给

[Kubernetes]Kubernetes的网络模型

Kubernetes的网络模型从内至外由四个部分组成: Pod内部容器所在的网络 Pod所在的网络 Pod和Service之间通信的网络 外界与Service之间通信的网络 建议在阅读本文之前先了解Docker的网络模型.可以参看作者的前两篇文章[Kubernetes]Docker的网络模型和[Kubernetes]Docker的overlay网络模型. 1. Pod内部容器所在的网络和Pod所在的网络 Kubernetes使用了一种"IP-per-pod"网络模型:为每一个Pod分配

BP神经网络模型与学习算法

一,什么是BP "BP(Back Propagation)网络是1986年由Rumelhart和McCelland为首的科学家小组提出,是一种按误差逆传播算法训练的多层前馈网络,是目前应用最广泛的神经网络模型之一.BP网络能学习和存贮大量的输入-输出模式映射关系,而无需事前揭示描述这种映射关系的数学方程.它的学习规则是使用最速下降法,通过反向传播来不断调整网络的权值和阈值,使网络的误差平方和最小.BP神经网络模型拓扑结构包括输入层(input).隐层(hide layer)和输出层(output