day 26

day 26

1. 软件开发架构

1.1 C/S架构

客户端与服务器端架构,这种架构也是从用户层面(也能够是物理层面)来划分的。python

这里的客户端通常泛指客户端应用程序EXE,程序须要先安装后,才能运行在用户的电脑上,对用户的电脑操做系统环境依赖较大。编程

CS架构

C: Client (客户端)设计模式

S: Server (服务端)浏览器

优势:缓存

  1. 客户端由于是独立设计,因此能够实现个性化。
  2. 由于客户端是须要进行安装的,能够不须要重复安装和加载。
  3. 由于客户端是独立开发的,因此有能力对客户端进行安全设计。

缺点:安全

  1. 由于客户端是不须要重复安装,因此用户能够不更新与升级,增长了维护成本。
  2. 由于须要开发客户端和服务器两套程序,因此开发成本会增长 。
  3. 兼容性差,若是遇到不一样的操做系统,须要为不一样的操做系统各开发一套客户端。

1.2 B/S架构

浏览器端与服务器端架构,这种架构是从用户层面来划分的。服务器

Browser浏览器,其实也是一种Client客户端,只是这个客户端不须要你们去安装什么应用程序,只需在浏览器上经过HTTP请求服务器端相关的资源(网页资源),客户端Browser浏览器就能进行增删改查。网络

BS架构

B: Browser ( 浏览器端 )架构

S: Server (服务端)并发

优势:

  1. 由于B/S架构具有通用性,因此开发成本较低。
  2. 由于不须要安装客户端,因此客户端不须要进行升级,只须要更新后台代码便可实现全部客户端的更新。
  3. 由于B/S架构多用WEB网页进行开发,因此增、删功能也很是容易,只须要修改网页便可完成。

缺点:

  1. 耗流量,每次都要加载所有的内容(不过有缓存能够下降流量损耗)。
  2. 由于没有独立的客户端,因此没法实现个性化(经过帐号体系能够实现)。
  3. 由于没有独立设计客户端,因此客户端难以实现安全控制(HTTPS、控件)。
  4. 难以实现特殊的操做(删本地文件),因此全部的杀毒软件都是C/S架构的。

总结:

CS架构响应速度快,安全性强,通常应用于局域网中,可是开发维护成本高;BS能够实现跨平台,客户端零维护,可是个性化能力低,响应速度较慢。

问题:数据放在服务端和客户端的利与弊?

  • 服务端统一处理有更好的安全性和稳定性并且升级比较容易,不过服务器负担就增长了。
  • 客户端将负担分配到每一个用户,从而能够节约服务器资源,安全性和稳定性可能会有必定的问题,可是升级比较麻烦,每一个安装的客户端程序都须要升级,另外为了节省网络资源,经过网络传输的数据应该尽可能减小!

2. 网络编程基础

2.1 以太网:局域网与交换机

局域网与交换机

2.1.1 以太网协议

对电信号来作分组。之前每一个公司都有本身的分组方式,后来造成了统一的标准,即以太网协议ethernet。

ethernet规定:一组电信号构成一个数据报,叫作'帧',每一数据帧分红:报头head和数据data两部分

  • head包含:(固定18个字节)
    • 发送者/源地址,6个字节
    • 接收者/目标地址,6个字节
    • 数据类型,6个字节
  • data包含:(最短46字节,最长1500字节)
- -
head data
  • 数据报的具体内容:head长度+data长度=最短64字节,最长1518字节,超过最大限制就分片发送

2.1.2 Mac地址

​ head中包含的源和目标地址由来:ethernet规定接入internet的设备都必须具有网卡,发送端和接收端的地址即是指网卡的地址,即mac地址。

  mac地址:每块网卡出厂时都被烧制上一个世界惟一的mac地址,长度为48位2进制,一般由12位16进制数表示(前六位是厂商编号,后六位是流水线号)

Mac地址

2.2 广播

主机之间“一对全部”的通信模式,网络对其中每一台主机发出的信号都进行无条件复制并转发,全部主机均可以接收到全部信息(无论你是否须要),因为其不用路径选择,因此其网络成本能够很低廉。有线电视网就是典型的广播型网络,咱们的电视机其实是接受到全部频道的信号,但只将一个频道的信号还原成画面。在数据网络中也容许广播的存在,但其被限制在二层交换机的局域网范围内,禁止广播数据穿过路由器,防止广播数据影响大面积的主机。

2.3 ip地址与ip协议

  • 规定网络地址的协议叫ip协议,它定义的地址称之为ip地址,普遍采用的v4版本即ipv4,它规定网络地址由32位2进制表示
  • 范围0.0.0.0-255.255.255.255
  • 一个ip地址一般写成四段十进制数,例:172.16.10.1

2.4 arp协议 ——经过IP地址去找MAC地址

  地址解析协议,即ARP(Address Resolution Protocol),是根据IP地址获取物理地址的一个TCP/IP协议。

  主机发送信息时将包含目标IP地址的ARP请求广播到网络上的全部主机,并接收返回消息,以此肯定目标的物理地址。

2.5 广域网与路由器

广域网与路由器

2.6 路由器

  路由器(Router),是链接因特网中各局域网、广域网的设备,它会根据信道的状况自动选择和设定路由,以最佳路径,按先后顺序发送信号。 路由器是互联网络的枢纽,"交通警察"。目前路由器已经普遍应用于各行各业,各类不一样档次的产品已成为实现各类骨干网内部链接、骨干网间互联和骨干网与互联网互联互通业务的主力军。路由和交换机之间的主要区别就是交换机发生在OSI参考模型第二层(数据链路层),而路由发生在第三层,即网络层。这一区别决定了路由和交换机在移动信息的过程当中需使用不一样的控制信息,因此说二者实现各自功能的方式是不一样的。

路由器(Router)又称网关设备(Gateway)是用于链接多个逻辑上分开的网络,所谓逻辑网络是表明一个单独的网络或者一个子网。当数据从一个子网传输到另外一个子网时,可经过路由器的路由功能来完成。所以,路由器具备判断网络地址和选择IP路径的功能,它能在多网络互联环境中,创建灵活的链接,可用彻底不一样的数据分组和介质访问方法链接各类子网,路由器只接受源站或其余路由器的信息,属网络层的一种互联设备。  

2.7 局域网

  局域网(Local Area Network,LAN)是指在某一区域内由多台计算机互联成的计算机组。通常是方圆几公里之内。局域网能够实现文件管理、应用软件共享、打印机共享、工做组内的日程安排、电子邮件和传真通讯服务等功能。局域网是封闭型的,能够由办公室内的两台计算机组成,也能够由一个公司内的上千台计算机组成。  

2.8 子网掩码

  所谓”子网掩码”,就是表示子网络特征的一个参数。它在形式上等同于IP地址,也是一个32位二进制数字,它的网络部分所有为1,主机部分所有为0。好比,IP地址172.16.10.1,若是已知网络部分是前24位,主机部分是后8位,那么子网络掩码就是11111111.11111111.11111111.00000000,写成十进制就是255.255.255.0。

  知道”子网掩码”,咱们就能判断,任意两个IP地址是否处在同一个子网络。方法是将两个IP地址与子网掩码分别进行AND运算(两个数位都为1,运算结果为1,不然为0),而后比较结果是否相同,若是是的话,就代表它们在同一个子网络中,不然就不是。

好比,已知IP地址172.16.10.1和172.16.10.2的子网掩码都是255.255.255.0,请问它们是否在同一个子网络?二者与子网掩码分别进行AND运算,

172.16.10.1:10101100.00010000.00001010.000000001
255255.255.255.0:11111111.11111111.11111111.00000000
AND运算得网络地址结果:10101100.00010000.00001010.000000001->172.16.10.0

 

172.16.10.2:10101100.00010000.00001010.000000010
255255.255.255.0:11111111.11111111.11111111.00000000
AND运算得网络地址结果:10101100.00010000.00001010.000000001->172.16.10.0
结果都是172.16.10.0,所以它们在同一个子网络

2.9 端口

咱们知道,一台拥有IP地址的主机能够提供许多服务,好比Web服务、FTP服务、SMTP服务等,这些服务彻底能够经过1个IP地址来实现。那么,主机是怎样区分不一样的网络服务呢?显然不能只靠IP地址,由于IP地址与网络服务的关系是一对多的关系。其实是经过“IP地址+端口号”来区分不一样的服务的。

3 OSI模型

人们按照分工不一样把互联网协议从逻辑上划分了层级:(通常做为开发人员,掌握应传网数物 五层便可):

OSI模型

每层运行常见物理设备:

每层常见的物理设备

每层运行常见的协议:

每层常见的协议

3.1 物理层

物理层链接

  • 构成

    网络通讯的数据传输介质,由链接不一样结点的电缆与设备共同构成。

  • 功能:

    基于电器特性发送高低电压(电信号),高电压对应数字1,低电压对应数字0。

3.2 数据链路层

  • 由来

    单纯的电信号0和1没有任何意义,必须规定电信号多少位一组,每组什么意思。

  • 功能

    基于以太网协议,定义了电信号的分组方式。

3.3 网络层

  • 功能

    引入一套新的地址用来区分不一样的广播域/子网,这套地址即网络地址

  • 由来

    有了ethernet、Mac地址、广播的发送方式,世界上的计算机就能够彼此通讯了,问题是世界范围的互联网是由 一个个彼此隔离的小的局域网组成的,那么若是全部的通讯都采用以太网的广播方式,那么一台机器发送的包全世界都会收到。

    广播

3.3.1 IP协议

用于标识惟一的一台计算机(局域网)的地址。

  • IP协议的做用
    • 为每一台计算机分配IP地址
    • 肯定哪些地址在同一个子网络

3.3.2 arp协议

  • 由来

    通讯是基于Mac的广播方式实现,计算机在发包时,获取自身的Mac是容易的,如何获取目标主机的Mac,就须要经过arp协议

  • 功能

    广播的方式发送数据包, 全部主机接收后拆开包,发现目标IP为本身的,就响应,返回本身的Mac。

3.4 传输层

  • 功能

    创建端口到端口的通讯

  • 由来

    网络层的IP帮咱们区分子网,以太网层的Mac帮咱们找到主机,而后你们使用的都是应用程序,你的电脑上可能同时开启qq,暴风影音,等多个应用程序。

    那么咱们经过IP和Mac找到了一台特定的主机,如何标识这台主机上的应用程序,答案就是端口,端口即应用程序与网卡关联的编号。

    有了Mac地址+IP地址+端口,咱们就能肯定世界上独一无二的一台计算机上的应用程序。

3.4.1 TCP协议

​ 可靠传输,TCP数据包没有长度限制,理论上能够无限长,可是为了保证网络的效率,一般TCP数据包的长度不会超过IP数据包的长度,以确保单个TCP数据包没必要再分割。

- - - -
以太网头 IP头 TCP头 数据

3.4.2 UDP协议

不可靠传输,”报头”部分一共只有8个字节,总长度不超过65,535字节,正好放进一个IP数据包。
- - - -
以太网头 IP头 UDP头 数据

3.5 应用层

  • 功能

    规定应用程序的数据格式。

  • 由来

    用户使用的都是应用程序,均工做于应用层,互联网是开发的,你们均可以开发本身的应用程序,数据多种多样,必须规定好数据的组织形式 。

4 传输控制协议

  • TCP协议:

    提供面向链接的服务,在传送数据以前必须先创建链接,数据传送完成后要释放链接。所以TCP是一种可靠的的运输服务,可是正由于这样,不可避免的增长了许多的开销,好比确认,流量控制等。对应的应用层的协议主要有 SMTP,TELNET,HTTP,FTP 等。

  • UDP协议:

    在传送数据前不须要先创建链接,远地的主机在收到UDP报文后也不须要给出任何确认。虽然UDP不提供可靠交付,可是正是由于这样,省去和不少的开销,使得它的速度比较快,好比一些对实时性要求较高的服务,就经常使用的是UDP。对应的应用层的协议主要有 DNS,TFTP,DHCP,SNMP,NFS 等。

  • 经常使用的端口号

    操做系统中,通常0-1024的端口都被默认使用了(0-1024不要动),尽可能使用8000以后的端口号。

    应用程序 FTP TFTP TELNET SMTP DNS HTTP SSH MYSQL
    熟知端口 21,20 69 23 25 53 80 22 3306
    传输层协议 TCP UDP TCP TCP UDP TCP TCP TCP

4.1 TCP协议

4.1.1 TCP创建链接(三次握手)

三次握手

  • 最开始的时候客户端和服务器都是处于CLOSED状态。主动打开链接的为客户端,被动打开链接的是服务器。
  1. TCP服务器进程先建立传输控制块TCB,时刻准备接受客户进程的链接请求,此时服务器就进入了LISTEN(监听)状态;
  2. TCP客户进程也是先建立传输控制块TCB,而后向服务器发出链接请求报文,这是报文首部中的同部位SYN=1,同时选择一个初始序列号 seq=x ,此时,TCP客户端进程进入了 SYN-SENT(同步已发送状态)状态。TCP规定,SYN报文段(SYN=1的报文段)不能携带数据,但须要消耗掉一个序号。
  3. TCP服务器收到请求报文后,若是赞成链接,则发出确认报文。确认报文中应该 ACK=1,SYN=1,确认号是ack=x+1,同时也要为本身初始化一个序列号 seq=y,此时,TCP服务器进程进入了SYN-RCVD(同步收到)状态。这个报文也不能携带数据,可是一样要消耗一个序号。
  4. TCP客户进程收到确认后,还要向服务器给出确认。确认报文的ACK=1,ack=y+1,本身的序列号seq=x+1,此时,TCP链接创建,客户端进入ESTABLISHED(已创建链接)状态。TCP规定,ACK报文段能够携带数据,可是若是不携带数据则不消耗序号。
  5. 当服务器收到客户端的确认后也进入ESTABLISHED状态,此后双方就能够开始通讯了。

4.1.2 TCP断开链接(四次挥手)

四次挥手

  • 数据传输完毕后,双方均可释放链接。最开始的时候,客户端和服务器都是处于ESTABLISHED状态,而后客户端主动关闭,服务器被动关闭。
  1. 客户端进程发出链接释放报文,而且中止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即便不携带数据,也要消耗一个序号。
  2. 服务器收到链接释放报文,发出确认报文,ACK=1,ack=u+1,而且带上本身的序列号seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,可是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。
  3. 客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送链接释放报文(在这以前还须要接受服务器发送的最后的数据)。
  4. 服务器将最后的数据发送完毕后,就向客户端发送链接释放报文,FIN=1,ack=u+1,因为在半关闭状态,服务器极可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。
  5. 客户端收到服务器的链接释放报文后,必须发出确认,ACK=1,ack=w+1,而本身的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP链接尚未释放,必须通过2∗ *∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。
  6. 服务器只要收到了客户端发出的确认,当即进入CLOSED状态。一样,撤销TCB后,就结束了此次的TCP链接。能够看到,服务器结束TCP链接的时间要比客户端早一些。

4.3 TCP协议中的问题

【问题1】为何链接的时候是三次握手,关闭的时候倒是四次握手?

答:由于当Server端收到Client端的SYN链接请求报文后,能够直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。可是关闭链接时,当Server端收到FIN报文时,极可能并不会当即关闭SOCKET,因此只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端全部的报文都发送完了,我才能发送FIN报文,所以不能一块儿发送。故须要四步握手。

【问题2】为何TIME_WAIT状态须要通过2MSL(最大报文段生存时间)才能返回到CLOSE状态?

答:虽然按道理,四个报文都发送完毕,咱们能够直接进入CLOSE状态了,可是咱们必须假象网络是不可靠的,有能够最后一个ACK丢失。因此TIME_WAIT状态就是用来重发可能丢失的ACK报文。在Client发送出最后的ACK回复,但该ACK可能丢失。Server若是没有收到ACK,将不断重复发送FIN片断。因此Client不能当即关闭,它必须确认Server接收到了该ACK。Client会在发送出ACK以后进入到TIME_WAIT状态。Client会设置一个计时器,等待2MSL的时间。若是在该时间内再次收到FIN,那么Client会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指一个片断在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。若是直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP链接。

【问题3】为何不能用两次握手进行链接?

答:3次握手完成两个重要的功能,既要双方作好发送数据的准备工做(双方都知道彼此已准备好),也要容许双方就初始序列号进行协商,这个序列号在握手过程当中被发送和确认。如今把三次握手改为仅须要两次握手,死锁是可能发生的。做为例子,考虑计算机S和C之间的通讯,假定C给S发送一个链接请求分组,S收到了这个分组,并发 送了确认应答分组。按照两次握手的协定,S认为链接已经成功地创建了,能够开始发送数据分组。但是,C在S的应答分组在传输中被丢失的状况下,将不知道S 是否已准备好,不知道S创建什么样的序列号,C甚至怀疑S是否收到本身的链接请求分组。在这种状况下,C认为链接还未创建成功,将忽略S发来的任何数据分 组,只等待链接确认应答分组。而S在发出的分组超时后,重复发送一样的分组。这样就造成了死锁。

【问题4】若是已经创建了链接,可是客户端忽然出现故障了怎么办?

TCP还设有一个保活计时器,显然,客户端若是出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会从新复位这个计时器,时间一般是设置为2小时,若两小时尚未收到客户端的任何数据,服务器就会发送一个探测报文段,之后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭链接。

5 Socket套接字

5.1 什么是Socket

Socket是应用层与TCP/IP协议族通讯的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来讲,一组简单的接口就是所有,让Socket去组织数据,以符合指定的协议。

因此,咱们无需深刻理解tcp/udp协议,socket已经为咱们封装好了,咱们只须要遵循socket的规定去编程,写出的程序天然就是遵循tcp/udp标准的。

5.2 套接字工做流程

socket流程

服务器端先初始化Socket,而后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端链接。在这时若是有个客户端初始化一个Socket,而后链接服务器(connect),若是链接成功,这时客户端与服务器端的链接就创建了。客户端发送数据请求,服务器端接收请求并处理请求,而后把回应数据发送给客户端,客户端读取数据,最后关闭链接,一次交互结束。

5.3 基于TCP协议的套接字编程

5.3.1 一次性通讯

# File-服务端.py
import socket

phone = socket.socket(socket.AF_INET,
                      socket.SOCK_STREAM)  #tcp称为流式协议,udp称为数据报协议SOCK_DGRAM

# phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(('127.0.0.1', 8081))

phone.listen(5)  # 半链接池,限制的是请求数

print('start....')
conn, client_addr = phone.accept()  #(三次握手创建的双向链接,(客户端的ip,端口))
print(conn)
print(client_addr)

#五、通讯:收\发消息
data = conn.recv(1024)  #最大接收的字节数
print('来自客户端的数据', data)
conn.send(data.upper())

#六、断开链接
conn.close()

#七、结束服务
phone.close()
# File-客户端.py
import socket

phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print(phone)

phone.connect(('127.0.0.1', 8081))  # 指定链接服务端ip和端口

#三、通讯:发\收消息
phone.send('hello'.encode('utf-8'))
# phone.send(bytes('hello',encoding='utf-8'))
data = phone.recv(1024)
print(data)

#四、关闭
phone.close()

5.3.2 循环通讯

# File-服务端.py
import socket

phone = socket.socket(socket.AF_INET,
                      socket.SOCK_STREAM)  #tcp称为流式协议,udp称为数据报协议SOCK_DGRAM

# phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(('127.0.0.1', 8080))

phone.listen(5)  # 半链接池,限制的是请求数

print('start....')
while True:  # 链接循环
    conn, client_addr = phone.accept()  #(三次握手创建的双向链接,(客户端的ip,端口))
    # print(conn)
    print('已经有一个链接创建成功', client_addr)

    #五、通讯:收\发消息
    while True:  # 通讯循环
        try:
            print('服务端正在收数据...')
            data = conn.recv(1024)  #最大接收的字节数,没有数据会在原地一直等待收,即发送者发送的数据量必须>0bytes
            # print('===>')
            if len(data) == 0: break  #在客户端单方面断开链接,服务端才会出现收空数据的状况
            print('来自客户端的数据', data)
            conn.send(data.upper())
        except ConnectionResetError:
            break
    #六、断开链接
    conn.close()

#七、中止服务
phone.close()
# File-客户端.py
import socket

phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

phone.connect(('127.0.0.1', 8080))  # 指定链接服务端ip和端口

#三、通讯:发\收消息
while True:  # 通讯循环
    msg = input('>>: ').strip()  #msg=''
    if len(msg) == 0: continue
    phone.send(msg.encode('utf-8'))
    # print('has send----->')
    data = phone.recv(1024)
    # print('has recv----->')
    print(data)

#四、断开链接
phone.close()
相关文章
相关标签/搜索