定义:node
在电的系统中,由若干元件组成的用来使电信号按必定要求传输的电路或这种电路的部分,叫网络。python
做为一名从事过TMN开发的通讯专业毕业生,执拗地认为网络是从通讯系统中诞生的。通讯是人与人之间经过某种媒介进行的信息交流与传递。传统的通讯网络(即电话网络)是由传输、交换和终端三大部分组成,通讯网络是指将各个孤立的设备进行物理链接,实现信息交换的链路,从而达到资源共享和通讯的目的。通讯网络能够从覆盖范围,拓扑结构,交换方式等诸多视角进行分类…… 满满的回忆,仍是留在书架上吧。web
网络的概念外延被不断的放大着,抽象的思惟能力是人们创新乃至创造的根源。网络用来表示诸多对象及其相互联系,数学上的图,物理学上的模型,交通网络,人际网络,城市网络等等,总之,网络被总结成从同类问题中抽象出来用数学中的图论科学来表达并研究的一种模型。算法
不少伙伴认为,了解这些以后呢,然并卵。咱们关心的只是计算机网络,算机网络是用通讯线路和设备将分布在不一样地点的多台计算机系统互相链接起来,按照网络协议,分享软硬件功能,最终实现资源共享的系统。特别的,咱们谈到的网络只是互联网——Internet,或者移动互联网,须要的是写互连网应用程序。可是,一位工做了五六年的编程高手曾对我说,如今终于了解到基础知识有多重要,技术在不断演进,而相对不变的就是那些原理和编程模型了。编程
老码农深觉得然,编程实践就是从具体到抽象,再到具体,循环往复,螺旋式上升的过程。了解前世此生,只是为了可能触摸到“势”。基础越扎实,建筑就会越有想象的空间。 对于网络编程的基础,大概要从OSI的七层协议模型开始了。设计模式
七层模型(OSI,Open System Interconnection参考模型),是参考是国际标准化组织制定的一个用于计算机或通讯系统间互联的标准体系。它是一个七层抽象的模型,不只包括一系列抽象的术语和概念,也包括具体的协议。 经典的描述以下:数组
简述每一层的含义:安全
物理层(Physical Layer):创建、维护、断开物理链接。服务器
数据链路层 (Link):逻辑链接、进行硬件地址寻址、差错校验等。网络
网络层 (Network):进行逻辑寻址,实现不一样网络之间的路径选择。
传输层 (Transport):定义传输数据的协议端口号,及流控和差错校验。
会话层(Session Layer):创建、管理、终止会话。
表示层(Presentation Layer):数据的表示、安全、压缩。
应用层 (Application):网络服务与最终用户的一个接口
每一层利用下一层提供的服务与对等层通讯,每一层使用本身的协议。了解了这些,然并卵。可是,这一模型确实是绝大多数网络编程的基础,做为抽象类存在的,而TCP/IP协议栈只是这一模型的一个具体实现。
TCP/IP是Internet的基础,是一组协议的代名词,包括许多协议,组成了TCP/IP协议栈。TCP/IP 有四层模型和五层模型之说,区别在于数据链路层是否做为独立的一层存在。我的倾向于5层模型,这样2层和3层的交换设备更容易弄明白。当谈到网络的2层或3层交换机的时候,就知道指的是那些协议。
数据是如何传递呢?这就要了解网络层和传输层的协议,咱们熟知的IP包结构是这样的:
IP协议和IP地址是两个不一样的概念,这里没有涉及IPV6的。不关注网络安全的话,对这些结构没必要耳熟能详的。传输层使用这样的数据包进行传输,传输层又分为面向链接的可靠传输TCP和数据报UDP。TCP的包结构:
TCP 链接创建的三次握手确定是必知必会,在系统调优的时候,内核中关于网络的相关参数与这个图息息相关。UDP是一种无链接的传输层协议,提供的是简单不可靠的信息传输。协议结构相对简单,包括源和目标的端口号,长度以及校验和。基于TCP和UDP的数据封装及解析示例以下:
仍是然并卵么?一个数据包的大小了解了,会发现什么?PayLoad究竟是多少?在设计协议通讯的时候,这些都为咱们提供了粒度定义的依据。进一步,经过一个例子看看吧。
FTP是一个比较好的例子。为了方便起见,假设两条计算机分别是A 和 B,将使用FTP 将A上的一个文件X传输到B上。
首先,计算机A和B之间要有物理层的链接,能够是有线好比同轴电缆或者双绞线经过RJ-45的电路接口链接,也能够是无线链接例如WIFI。先简化一下,考虑局域网,暂不讨论路由器和交换机以及WIFI热点。这些物理层的链接创建了比特流的原始传输通路。
接下来,数据链路层登场,创建两台计算机的数据链路。若是A和B所在的网络上同时链接着计算机C,D,E等等,A和B之间如何创建的数据链路呢?这一过程就是物理寻址,A要在众多的物理链接中找到B,依赖的是计算机的物理地址即MAC地址,对就是网卡上的MAC地址。以太网采用CSMA/CD方式来传输数据,数据在以太网的局域网中都是以广播方式传输的,整个局域网中的全部节点都会收到该帧,只有目标MAC地址与本身的MAC地址相同的帧才会被接收。A经过差错控制和接入控制找到了B的网卡,创建可靠的数据通路。
那IP地址呢? 数据链路创建起来了,还须要IP地址么?咱们FTP 命令中制定的是IP地址而不是MAC地址呀?IP地址是逻辑地址,包括网络地址和主机地址。若是A和B在不一样的局域网中,中间有着多个路由器,A须要对B进行逻辑寻址才能够的。物理地址用于底层的硬件的通讯,逻辑地址用于上层的协议间的通讯。在以太网中:逻辑地址就是IP地址,物理地址就是MAC 地址。在使用中,两种地址是用必定的算法将他们两个联系起来的。因此,IP是用来在网络上选择路由的,在FTP的命令中,IP中的原地址就是A的IP地址,目标地址就是B的IP地址。这应该就是网络层,负责将分组数据从源端传输到目的端。
A向B传输一个文件时,若是文件中有部分数据丢失,就可能会形成在B上没法正常阅读或使用。因此须要一个可靠的链接,可以确保传输过程的完整性,这就是传输层的TCP协议,FTP就是创建在TCP之上的。TCP的三次握手肯定了双方数据包的序号、最大接受数据的大小(window)以及MSS(Maximum Segment Size)。TCP利用IP完成寻址,TCP中的提供了端口号,FTP中目的端口号通常是21。传输层的端口号对应主机进程,指本地主机与远程主机正在进行的会话。
会话层用来创建、维护、管理应用程序之间的会话,主要功能是对话控制和同步,编程中所涉及的session是会话层的具体体现。表示层完成数据的解编码,加解密,压缩解压缩等,例如FTP中bin命令,表明了二进制传输,即所传输层数据的格式。
HTTP协议里body中的Json,XML等均可以认为是表示层。应用层就是具体应用的自己了,FTP中的PUT,GET等命令都是应用的具体功能特性。
简单地,物理层到电缆链接,数据链路层到网卡,网络层路由到主机,传输层到端口,会话层维持会话,表示层表达数据格式,应用层就是具体FTP中的各类命令功能了。
了解了7层模型就能够编程了么,拿起编程语言就能够耍了么?刚开始上手尝试仍是能够的,若是要进一步,老码农以为仍是看看底层实现的好,由于一切归根到底都会归结为系统调用。到了操做系统层面如何看网络呢?Socket登场了。
在Linux世界,“一切皆文件”,操做系统把网络读写做为IO操做,就像读写文件那样,对外提供出来的编程接口就是Socket。因此,socket(套接字)是通讯的基石,是支持TCP/IP协议网络通讯的基本操做单元。socket实质上提供了进程通讯的端点。进程通讯以前,双方首先必须各自建立一个端点,不然是没有办法创建联系并相互通讯的。一个完整的socket有一个本地惟一的socket号,这是由操做系统分配的。
从设计模式的角度看, Socket实际上是一个外观模式,它把复杂的TCP/IP协议栈隐藏在Socket接口后面,对用户来讲,一组简单的Socket接口就是所有。当应用程序建立一个socket时,操做系统就返回一个整数做为描述符(descriptor)来标识这个套接字。而后,应用程序以该描述符为传递参数,经过调用函数来完成某种操做(例如经过网络传送数据或接收输入的数据)。以TCP 为例,典型的Socket 使用以下:
在许多操做系统中,Socket描述符和其余I/O描述符是集成在一块儿的,操做系统把socket描述符实现为一个指针数组,这些指针指向内部数据结构。进一步看,操做系统为每一个运行的进程维护一张单独的文件描述符表。当进程打开一个文件时,系统把一个指向此文件内部数据结构的指针写入文件描述符表,并把该表的索引值返回给调用者 。
既然Socket和操做系统的IO操做相关,那么各操做系统IO实现上的差别会致使Socket编程上的些许不一样。看看我Mac上的Socket.so 会发现和CentOS上的仍是些不一样的。
进程进行Socket操做时,也有着多种处理方式,如阻塞式IO,非阻塞式IO,多路复用(select/poll/epoll),AIO等等。
多路复用每每在提高性能方面有着重要的做用。select系统调用的功能是对多个文件描述符进行监视,当有文件描述符的文件读写操做完成以及发生异常或者超时,该调用会返回这些文件描述符。select 须要遍历全部的文件描述符,就遍历操做而言,复杂度是 O(N)。
epoll相关系统调用是在Linux 2.5 后的某个版本开始引入的。该系统调用针对传统的select/poll不足,设计上做了很大的改动。select/poll 的缺点在于:
每次调用时要重复地从用户模式读入参数,并重复地扫描文件描述符。
每次在调用开始时,要把当前进程放入各个文件描述符的等待队列。在调用结束后,又把进程从各个等待队列中删除。
epoll 是把 select/poll 单个的操做拆分为 1 个 epoll_create,多个 epoll_ctrl和一个 wait。此外,操做系统内核针对 epoll 操做添加了一个文件系统,每个或者多个要监视的文件描述符都有一个对应的inode 节点,主要信息保存在 eventpoll 结构中。而被监视的文件的重要信息则保存在 epitem 结构中,是一对多的关系。因为在执行 epoll_create 和 epoll_ctrl 时,已经把用户模式的信息保存到内核了, 因此以后即使反复地调用 epoll_wait,也不会重复地拷贝参数,不会重复扫描文件描述符,也不反复地把当前进程放入/拿出等待队列。
因此,当前主流的Server侧Socket实现大都采用了epoll的方式,例如Nginx, 在配置文件能够显式地看到 use epoll。
了解了7层协议模型和操做系统层面的Socket实现,能够方便咱们理解网络编程。
在系统架构的时候,有重要的一环就是拓扑架构,这里涉及了网络等基础设施,那么7层协议下四层就会有助于咱们对业务系统网络结构的观察和判断。在系统设计的时候,每每采用面向接口的设计,而接口也每每是基于HTTP协议的Restful API。 那接口的粒度就能够将data segment做为一个约束了,同时能够关注到移动互联网中的弱网环境。
不一样的编程语言,有着不一样的框架和库,真正的编写网络程序代码并不复杂,例如,用Erlang 中 gen_tcp 用于编写一个简单的Echo服务器:
然而,写出漂亮的服务器程序仍然是一件很是吃功夫的事情,例如,我的很是喜欢的python Tornado 代码, 在ioloop.py 中有对多路复用的选择:
在HTTPServer.py 中一样继承了TCPServer,进而实现了HTTP协议,代码片断以下:
或许,老码农说的都是错的,了解了所谓的网络基础,也不必定写出漂亮的代码,不了解所谓的网络基础,也不必定写不出漂亮的代码,全当他自言自语吧。