网络模型的简介
网络技术是从1990年代中期发展起来的新技术,它把互联网上分散的资源融为有机整体,实现资源的全面共享和有机协作,使人们能够透明地使用资源的整体能力并按需获取信息,资源包括高性能计算机、存储资源、数据资源、信息资源、知识资源、专家资源、大型数据库、网络、传感器等.
网络编程是实现各类网络应用程序的基础,现在大部分的网络应用程序都基于Socket通信的,网络通信协议一共有两种,一种是基于OSI的7层参考模型,而另一种则是TCP/IP协议的4层通信模型,在我们开发环境中会使用TCP/IP作为通信基础,接下来将具体介绍两种通信协议模型.
网络编程最主要的工作就是在发送端把信息通过规定好的协议进行组装包,在接收端按照规定好的协议把包进行解析,从而提取出对应的信息,达到通信的目的.中间最主要的就是数据包的组装,数据包的过滤,数据包的捕获,数据包的分析,当然最后再做一些处理.
◆OSI 参考模型◆
1983年,国际标准化组织(International Organization for standardization,ISO)发布了著名的ISO/IEC 7498标准,也就是开放式系统互连参考模型OSI,这个标准定义了网络的七层框架,试图使计算机在整个世界范围内实现互联,其中这七层分别的含义如下:
以上的列表是一个通用的网络系统模型,并不是一个协议定义.实际上OSI模型从来没有被真正实现过,但是,出于其模型的广泛指导性,现在的网络协议都已经纳入了OSI参考模型的范围之内,OSI参考模型一共有7层,每层的作用在上面有说明,这也是网络方面的基础知识.
◆TCP/IP 参考模型◆
其实早在OSI模型出现之前,就已经有了TCP/IP的研究和实现,时间最早可以追溯到20世纪70年代,为互联网的最旱的通信协议,TCP为传输层的协议,而IP则为网络层的协议,两个层次中有代表性的协议组合代表了一系列的协议族,还包括有 ARP、ICMP 和 UDP 协议等,山于TCP/IP协议出现的比OSI早,所以井不符合OSI模型,他们的对应关系是这样的,如下表所示.
以上的两个列表左边是OSI模型,右边是TCP/IP模型,从列表可以看到,TCP/IP模型并不关心IP层以下的组成,而是将数据输出统一成了网络接口层,这样一来,IP层只需要将数据发往网络接口层就可以了,而不需要关心下层具体的操作.而在OSI模型中,则将这些功能分成了数据链路层和物理层,而且还进行了进一步的划分,在传输层和网络层大部分还是一致的,而对于OSI中的上面三层,则在TCP/IP模型中合将其合并成了应用层.
在现在的互联网中,主要采用TCP/IP协议,这已经成为了互联网上通信的事实标准,现在TCP/IP协议已经可以运行在各种信道和底层协议之上.
◆Socket 基础知识◆
套接字(Sockct)随着 TCP/IP协议的使用,也越来越多地被使用在网络应用程序的构建中,实际上 Socket编程也已经成为了网络中传送和接收数据的首选方法,套接字最早是由伯克利在BSD中推出的一种进程间通信方案和网络互联的基本机制,现在已经有多种相关的套接字实现,但大部分还是遵循着最初的设计要求.
Socket通常也称作”套接字”,用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过”套接字”向网络发出请求或者应答网络请求,Socket起源于Unix而Unix/Linux基本哲学之一就是”一切皆文件”,Socket就是文件模式的一个实现,Socket即是一种特殊的文件,一些Socket函数就是对其进行的操作(读/写IO、打开、关闭)等.
Pythhon 标准库中支持套接口的模块是Socket,其中包含生成套接字、等待连接、建立连接和传输数据的方法,任何应用程序需要使用套接字,都必须调用Socket方法生成一个套接字对象,对于服务器端而言,首先需要调用 bind 方法绑定一个套接口地址,接着使用 listen 方法开始监听客户端请求.当有客户端请求过来的时候,将通过 accept 方法来生成一个连接对象,然后就可以通过此连接对发送和接收数据了,数据传输完毕后可以调用 close 方法将生成的连接关闭.
服务端与客户端
Socket 常用地址簇:
socket.AF_UNIX unix进程间通信
socket.AF_INET ipv4
socket.AF_INET6 ipv6
Socket 常用地址簇:
socket.SOCK 裸套接字
socket.SOCK_STREAM TCP通信
socket.SOCK_DGRAM UDP通信
SOCK_RAW 原始套接字,可处理ICMP、IGMP等网络报文
SOCK_RDM 是一种可靠的UDP形式,即保证交付数据报但不保证顺序
SOCK_SEQPACKET 可靠的连续数据包服务
常用方法:
◆实现TCP传输◆
服务端: 首先启动服务端,然后服务端会创建套接字,并绑定localhost:9999端口,设置最大连接数为5,然后发送数据.
客户端: 客户端启动后,创建套接字,并主动连接localhost:9999端口,等待接收数据,并根据接收到的数据做回复.
◆实现UDP传输◆
UDP服务端: UDP服务端绑定端口,并等待接收数据,收到数据后返回一个OK作为结束.
UDP客户端: 客户端绑定IP地址,然后发送数据,并等待服务端回应OK作为结束.
◆实现文件传输◆
服务端: 首先服务端打开文件并计算大小后,发送给客户端文件的大小,并等待传输数据.
客户端: 客户端收到文件大小后,开始接收数据,每次接收完数据以后累加,直到全部传输完成以后退出循环.
传输文件(简单写法): Socket也可以实现远程文件的传输,比如以下代码就实现了服务端向客户端传递数据的过程.
传输文件(完整写法):
Socket Server
SocketServer 是标准库中一个高级的网络处理模块,用于简化网络客户与服务器的实现(在前面使用Socket的过程中,我们先设置了Socket的类型,然后依次调用bind(),listen(),accept()最后使用while循环来让服务器不断的接受请求,而这些步骤可以通过SocketServer包来简化),模块中已经实现了一些可供使用的类.
SocketServer 内部使用IO多路复用以及”多线程”和”多进程”,从而实现并发处理多个客户端请求的Socket服务端,即每个客户端请求连接到服务器时,Socket服务端都会在服务器是创建一个”线程”或”进程”专门负责处理当前客户端的所有请求,底层还是对socket进行了封装和加入线程、进程就实现了进一步对Socket函数的二次封装.
◆简单的线程交互◆
服务端:
客户端:
◆高级多线程交互◆
服务端:
客户端:
异步IO数据通信
在上面的实例中除了SocketServer的内容外,其他的服务器端的实现都是同步的,也就是说,服务程序只有处理完一个连接后,才能处理另外一个连接,如果需要让服务器端应用程序能够同时处理多个连接,则需要使用异步通信方式.
当同时有多个连接的时候,采用SocketServer和线程的方式都可以,但是对于那种持续时间长且数据突发的多连接,前面的这些处理方式所占用的资源太大,一种改进的方式是在一定的时间段内查看已有的连接并处理,处理的过程包括读取数据和发送数据,在 Python 标准库中包含了一种专门的异步IO通信方式,它就是select模块.
同步机制 && 异步机制
● 同步机制:调用发出之后不会立即返回,进程会一直询问内核准备好数据没有,但一旦返回,则内核返回最终结果,数据已经从内核内存复制到进程内存了,这种方式没有通知机制.
● 异步机制:调用发出之后,被调用方立即返回消息,但返回的并非最终结果,被调用者通过状态、通知机制来通知调用者,或通过回调函数来处理,这种方式有有通知机制.
阻塞IO && 非阻塞IO
● 阻塞IO:当用户线程发起一个IO请求操作,内核会去查看要读取的数据是否就绪,如果数据没有就绪,则会一直等待,直到数据就绪,当数据就绪之后,便将数据拷贝到用户线程,最后结束整个过程.
● 非阻塞IO:当用户线程发起一个IO请求操作,内核会去查看要读取的数据是否就绪,如果数据没有就绪,如果数据没有就绪,则会返回一个标志信息告知用户线程当前要读的数据没有就绪.
● 阻塞(blocking IO),非阻塞(non-blocking IO)的区别就在于第一个阶段,如果数据没有就绪,在查看数据是否就绪的过程中是一直等待,还是直接返回一个标志信息.
常用异步机制 Select,Poll,Epoll
● select 最早于1983年出现在4.2BSD中,目前所有的平台上都支持,但select的一个缺点在于单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024个文件.
● poll在1986年诞生于System V Release 3,它和select在本质上没有多大差别,但是poll没有最大文件描述符数量的限制,它的开销随着文件描述符数量的增加而增大.
● epoll 直到Linux2.6才出现了由内核直接支持的实现方法,它几乎具备了之前所说的一切优点,被公认为Linux2.6下性能最好的多路I/O就绪通知方法,理论上边缘触发的性能要更高一些,但是代码实现相当复杂.
◆Select◆
Select 的使用方法是监视指定的文件描述符,并在文件描述符集改变的时候做出响应,在Python标准库中,具体的实现了Select模块中的Select方法,这实际上也是Select系统调用的一个接口.
Select 服务端: 使用Select模块构建并发环境,在单线程下实现多并发的要求.
Select 客户端: 客户端直接绑定服务端的IP地址,只需要简单的实现数据的收发即可.
此处的Socket服务端相比与原生的Socket,他支持当某一个请求不再发送数据时,服务器端不会等待而是可以去处理其他请求的数据.但是,如果每个请求的耗时比较长,select版本的服务器端也无法完成同时操作.
◆Selectors◆
Selectors 模块,是在Python 3.x以后加入的新模块,其实就是在Select的基础之上进行了更加深入的封装,但是需要注意的是,Selectors模块会根据用户所在的平台的不同来选择性的使用select或者是epoll,对用户来说是透明的,但是还是需要注意这一点,但是此模块如果不做后端开发,一般也很少使用,这里了解即可.
服务端:
客户端:
TCP 实现的通信
client
server
lib套接字通信
server
client
未完待续
server
client