python-day31(正式学习)

1、单机架构python

应用领域:linux

  • 植物大战僵尸
  • office

2、CS架构面试

149-网络架构及其演变过程-cs架构.jpg?x-oss-process=style/watermark

应用领域:数据库

  • QQ
  • 大型网络游戏

计算机发展初期用户去取数据,直接就去主机拿,从这里开始就分出了客户端和服务端。编程

客户端:用户安装的软件;设计模式

服务端:统一管理数据库的主机中的软件就叫作服务端,再后来服务端不仅是管理数据,外加处理业务逻辑。浏览器

2.1 CS架构要求缓存

  1. 用户操做系统安装客户端;产商操做系统部署服务端
  2. 每一个用户须要独立安装软件、服务端升级也要每一个用户升级

2.2 面试题:数据放在服务端和客户端的利与弊?安全

答:服务器

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

3、BS架构

149-网络架构及其演变过程-bs架构.jpg?x-oss-process=style/watermark

应用领域:

  • 淘宝
  • 京东

统一客户端即默认安装用户电脑中的浏览器,访问同种类的网站,具体业务的处理根据相应协议和标准提供通用的服务器程序,在不一样的服务器处理。

3.1 两种BS架构

149-网络架构及其演变过程-osi和tcp.jpg?x-oss-process=style/watermark

OSI主要用于教学(万恶的大学、绿本的计算机书),咱们在编程的时候用的都是TCP/IP。

TCP/IP的对应关系,就像咱们在淘宝购物,所在位置有的快递(网络接入层),告诉卖家地址(网络互联层)、快递送货(运输层)、收到货物拆包使用(应用层)。

注意:对于普遍使用的东西就须要制定相应的标准,就像大公司有不少制度来规范作事情的流程。因为网络传输应用很是普遍,可是规矩不是强制性的,因此叫作协议而不是标准,TCP/IP参考模型也能够看作是一种协议。BS结构中TCP/IP模型中的网络接入层没有响应的协议,网络互联层是IP协议,传输层是TCP协议,应用层是HTTP协议,另外仍是用到了DNS结构,并且在HTTP上层还有相应。

基于BS结构下的程序就要求解决速度问题,而速度问题的核心就是解决海量数据操做和高并发问题,网站复杂架构就是从这两个问题演变出来的。

4、CS架构和BS架构区别

149-网络架构及其演变过程-csbs区别.jpg?x-oss-process=style/watermark

互联网的本质就是一系列的网络协议,这个协议就叫OSI协议(一系列协议),按照功能不一样,分工不一样,人为的分层七层。实际上这个七层是不存在的。没有这七层的概念,只是人为的划分而已。区分出来的目的只是让你明白哪一层是干什么用的。

每一层都运行不一样的协议。协议是干什么的,协议就是标准。

实际上还有人把它划成五层、四层。

七层划分为:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层。

五层划分为:应用层、传输层、网络层、数据链路层、物理层。

四层划分为:应用层、传输层、网络层、网络接口层。

151-大白话OSI七层协议-七层协议.jpg?x-oss-process=style/watermark

每层运行常见的物理设备

151-大白话OSI七层协议-物理设备.jpg?x-oss-process=style/watermark

1、物理层

物理层功能:主要是基于电器特性发送高低电压(电信号),高电压对应数字1,低电压对应数字0

物理层字面意思解释:物理传输、硬件、物理特性。在深圳的你与北京的朋友聊天,你的电脑必需要能上网,物理体现是什么?是否是接一根网线,插个路由器,北京的朋友那边是否是也有根网线,也得插个路由器。也就是说计算机与计算机之间的通讯,必需要有底层物理层方面的连通,就相似于你打电话,中间是否是必须得连电话线。

中间的物理连接能够是光缆、电缆、双绞线、无线电波。中间传的是电信号,即010101...这些二进制位。

151-大白话OSI七层协议-物理层.jpg?x-oss-process=style/watermark

底层传输的010010101001...这些二进制位怎么才能让它有意义呢?

151-大白话OSI七层协议-物理层1.jpg?x-oss-process=style/watermark

要让这些010010101001...有意思,人为的分组再适合不过了,8位一组,发送及接收都按照8位一组来划分。接收到8位为一组的话,那么就能够按照这8位数来作运算。若是没有分组,对方接收的计算机根本就不知道从哪一位开始来作计算,也解析不了收到的数据。我发了16位你就按照16位来作计算吗?我发100位你就按照100位作计算吗?没什么意义是吧。所以要想让底层的电信号有意义,必需要把底层的电信号作分组。我作好8位一组,那么我收到数据,我就知道这几个8位作一组,这几个8位作一组。那么每一个8位就能够获得一个肯定的数。分组是谁干的活呢?物理层干不了,这个是数据链路层干的。

2、数据链路层

数据链路层由来:单纯的电信号0和1没有任何意义,必须规定电信号多少位一组,每组什么意思

数据链路层的功能:定义了电信号的分组方式

2.1 以太网协议

早期的时候,数据链路层就是来对电信号来作分组的。之前每一个公司都有本身的分组方式,后来造成了统一的标准,即以太网协议ethernet

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

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

这就像写信,发送者的地址(源地址)就是你家的地址,接收者地址(目标地址)就是对方的收信地址,你家的路由器就至关于邮局。其实在计算机通讯中的源地址和目标地址指的是Mac地址。

2.2 Mac地址

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

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

151-大白话OSI七层协议-mac网卡1.png?x-oss-process=style/watermark

151-大白话OSI七层协议-mac地址.jpg?x-oss-process=style/watermark

2.3 广播地址

有了Mac地址之后,计算机就能够通讯了,假设一个教室就是一个局域网(隔离的网络),这个教室里面有几台计算机,计算机的通讯和人的通讯是一个道理,把教室里面的人都比做一个个计算机,假设教室里面的人都是瞎子,其实计算机就是瞎子的,计算机通讯基本靠吼,如今我要找教室里面的飞哥要战狼2的片,而后我就吼一声,说我要找飞哥要战狼2的片,战狼2的片就属于个人数据,可是我在发的时候我是否是要标识我是谁,我要找谁,我是谁就是个人Mac地址,我要找谁就是飞哥的Mac地址,这两个地址作数据包的头部,再加上数据战狼2的片就构成了一个数据帧。

这个数据包封装好之后就往外发,到物理层之后就所有转成二进制,往外发是怎么发的呢?就是靠吼。即“我是nick,我找飞哥要战狼2的片”。这么吼了一嗓子之后,全屋子的人都能听到,这就是广播。

计算机底层,只要在一个教室里(一个局域网),都是靠广播的方式,吼。

151-大白话OSI七层协议-广播.jpg?x-oss-process=style/watermark

广播出去之后,全部人都听得见,全部人都会拆开这个包,读发送者是谁,接收者是谁,只要接收者不是本身就丢弃掉。对计算机来讲,它会看本身的Mac地址,飞哥收到之后,他就会把片发给我,发送回来一样采用广播的方式了,靠吼。

同一个教室(同一个局域网)的计算机靠吼来通讯,那不一样教室的计算机又如何?

好比说局域网1的pc1与局域网2的pc10如何通讯?你在教室1(局域网1)吼,教室2(局域网2)的人确定是听不见的。这就是跨网络进行通讯,数据链路层就解决不了这个问题了,这就得靠网络层出面了。

注意:在讲网络层以前,其实基于广播的这种通讯就能够实现全世界通讯了,你吼一声,若是全世界是一个局域网,全世界的计算机确定能够听得见,从理论上彷佛行得通,若是全世界的计算机都在吼,你想想,这是否是一个灾难。所以,全世界不能是一个局域网。因而就有了网络层。

3、网络层

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

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

  • 对于上述的问题这就不只仅是效率低的问题了,这会是一种灾难

151-大白话OSI七层协议-网络层.jpg?x-oss-process=style/watermark

为了解决上述灾难,网络层定义了一个IP协议,

你想,我是这个教室的一个学生,我想找隔壁教室一个叫老王的学生,我也不认识老王,那怎么办,我吼?老王在另一个教室确定是听不到的。找教室的负责人,这个教室的负责人就负责和隔壁教室的负责人说话,说咱们教室的有个学生要找大家教室的老王。往外传的东西交给负责人就能够了,内部的话上面已经提到,经过广播的方式,对外的东西广播失效。教室的负责人就是网关,网关即网络关口的意思。

Mac地址是用来标识你这个教室的某个位置,IP地址是用来标识你在哪一个教室(哪一个局域网)。你要跨网络发包你是否是要知道对方的IP地址,好比你要访问百度,你确定得知道百度服务器的IP地址。计算机在发包前,会判断你在哪一个教室,对方在哪一个教室,若是在一个教室,基于Mac地址的广播发包就OK了;若是不在一个教室,即跨网络发包,那么就会把你的包交给教室负责人(网关)来转发。Mac地址及IP地址惟一标识了你在互联网中的位置。

数据链路层中会把网络层的数据包封装到数数据链路层的数据位置,而后再添加上本身的包头,再发给物理层,物理层发给网关,网关再发给对方教室的网关,对方教室的网关收到后在那个教室作广播。

在数据链路层看,数据封装了两层,跟玩俄罗斯套娃有点相似,一层套了一层。

151-大白话OSI七层协议-网络层包.jpg?x-oss-process=style/watermark

最终变成

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

如今来看另外一个问题,在吼以前怎么知道对方的Mac地址?这就得靠ARP协议。

ARP协议的由来:在你找飞哥要片以前,你的先干一件事,想办法知道飞哥的Mac地址。即你的机器必须先发一个ARP包出去,ARP也是靠广播的方式发,ARP发送广播包的方式以下:

- 源Mac 目标Mac 源IP 目标IP 数据部分
发送端主机 发送端Mac FF:FF:FF:FF:FF:FF 172.16.10.10/24 172.16.10.11/24 数据

局域网中怎么获取对方的Mac地址:

确定要知道对方的IP地址,这是最基本的,就像你要访问百度,确定得知道百度的域名,域名就是百度的IP地址。本身的IP能够轻松得到,本身的Mac也轻松获取,目标Mac为12个F,咱们叫广播地址,表达的意思是我想要获取这个目标IP地址172.16.10.11的机器的Mac地址。Mac为12个F表明的是一种功能,这个功能就是获取对方的Mac地址,计算机的Mac永远不多是12个F。假设是在本教室广播,一嗓子吼出去了,全部人开始解包,只有IP地址是172.16.10.11的这我的才会返回他的Mac地址,其余人所有丢弃。发回来源Mac改为飞哥本身的Mac地址,同时把飞哥的Mac地址放在数据部分。

跨网络怎么获取对方的Mac地址:

经过IP地址区分,计算机运算判断出飞哥不在同一个教室,目标IP就变成了网关的IP了。网关的IP在计算机上配死了,能够轻松获取。

- 源Mac 目标Mac 源IP 目标IP 数据部分
发送端主机 发送端Mac FF:FF:FF:FF:FF:FF 172.16.10.10/24 172.16.10.11/24 数据
- 源Mac 目标Mac 源IP 目标IP 数据部分
发送端主机 发送端Mac FF:FF:FF:FF:FF:FF 172.16.10.10/24 网关地址 数据
- 源Mac 目标Mac 源IP 目标IP 数据部分
发送端主机 发送端Mac 网关Mac 172.16.10.10/24 飞哥的IP 数据

注意:网关帮你去找飞哥,但对用户来讲,因为速度太快咱们根本就感受不到网关的存在。

3.1 IP协议详解

规定网络地址的协议叫IP协议,它定义的地址称之为IP地址,普遍采用的v4版本即IPv4,它规定网络地址由32位2进制表示
范围0.0.0.0-255.255.255.255

  • 一个IP地址一般写成四段十进制数,例:172.16.10.1

3.1.1 IP地址的两部分

  1. 网络部分:标识子网
  2. 主机部分:标识主机
  • 注意:单纯的IP地址段只是标识了IP地址的种类,从网络部分或主机部分都没法辨识一个IP所处的子网

例:172.16.10.1与172.16.10.2并不能肯定两者处于同一子网

3.2 子网掩码详解

所谓”子网掩码”,就是表示子网络特征的一个参数。它在形式上等同于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
    • 255.255.255.0:11111111.11111111.11111111.00000000
    • AND运算得网络地址结果:10101100.00010000.00001010.000000000->172.16.10.0
  • 172.16.10.2:10101100.00010000.00001010.000000010
    • 255.255.255.0:11111111.11111111.11111111.00000000
    • AND运算得网络地址结果:10101100.00010000.00001010.000000000->172.16.10.0
  • 结果都是172.16.10.0,所以它们在同一个子网络。

总结一下,IP协议的做用主要有两个,一个是为每一台计算机分配IP地址,另外一个是肯定哪些地址在同一个子网络。

3.3 IP数据包详解

IP数据包也分为head和data部分,无须为IP包定义单独的栏位,直接放入以太网包的data部分

  • head:长度为20到60字节
  • data:最长为65,515字节

注意:以太网数据包的"数据"部分,最长只有1500字节。所以,若是IP数据包超过了1500字节,它就须要分割成几个以太网数据包,分开发送了。

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

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

3.4 ARP协议详解

arp协议由来:计算机通讯基本靠吼,即广播的方式,全部上层的包到最后都要封装上以太网头,而后经过以太网协议发送,在谈及以太网协议时候,我门了解到:通讯是基于Mac的广播方式实现,计算机在发包时,获取自身的Mac是容易的,如何获取目标主机的Mac,就须要经过arp协议

arp协议功能:广播的方式发送数据包,获取目标主机的Mac地址

协议工做方式:每台主机IP都是已知的,例如:主机172.16.10.10/24访问172.16.10.11/24

1.首先经过IP地址和子网掩码区分出本身所处的子网

场景 数据包地址
同一子网 目标主机Mac,目标主机IP
不一样子网 网关Mac,目标主机IP

2.分析172.16.10.10/24与172.16.10.11/24处于同一网络(若是不是同一网络,那么下表中目标IP为172.16.10.1,经过arp获取的是网关的Mac)

- 源Mac 目标Mac 源IP 目标IP 数据部分
发送端主机 发送端Mac FF:FF:FF:FF:FF:FF 172.16.10.10/24 172.16.10.11/24 数据

3.这个包会以广播的方式在发送端所处的自网内传输,全部主机接收后拆开包,发现目标IP为本身的,就响应,返回本身的Mac

4、传输层

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

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

传输层功能:创建端口到端口的通讯

补充:端口范围0-65535,0-1023为系统占用端口

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

4.1 TCP协议

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

4.2 UDP协议

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

4.3 TCP报文

151-大白话OSI七层协议-tcp报文.jpg?x-oss-process=style/watermark

4.4 TCP三次握手和四次挥手

151-大白话OSI七层协议-tcp三次握手和四次挥手.jpg?x-oss-process=style/watermark

5、应用层

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

应用层功能:规定应用程序的数据格式。

  • 例:TCP协议能够为各类各样的程序传递数据,好比Email、WWW、FTP等等。那么,必须有不一样协议规定电子邮件、网页、FTP数据的格式,这些应用程序协议就构成了”应用层”。

151-大白话OSI七层协议-应用层.jpg?x-oss-process=style/watermark

注意:数据通过以上几层的折腾,已经不成样子了。

151-大白话OSI七层协议-七层数据内容.jpg?x-oss-process=style/watermark

1、背景描述

经过OSI七层网络模型中IP层的介绍,咱们知道网络层,能够实现两个主机之间的通讯。可是这并不具体,由于,真正进行通讯的实体是在主机中的进程,是一个主机中的一个进程与另一个主机中的一个进程在交换数据。IP协议虽然能把数据报文送到目的主机,可是并无交付给主机的具体应用进程。而端到端的通讯才应该是应用进程之间的通讯。

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

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

2、经常使用的熟知端口号

应用程序 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

3、TCP概述

TCP把链接做为最基本的对象,每一条TCP链接都有两个端点,这种端点咱们叫做套接字(socket),它的定义为端口号拼接到IP地址即构成了套接字,例如,若IP地址为192.3.4.16 而端口号为80,那么获得的套接字为192.3.4.16:80。

4、TCP报文首部

  1. 源端口和目的端口,各占2个字节,分别写入源端口和目的端口;
  2. 序号,占4个字节,TCP链接中传送的字节流中的每一个字节都按顺序编号。例如,一段报文的序号字段值是 301 ,而携带的数据共有100字段,显然下一个报文段(若是还有的话)的数据序号应该从401开始;
  3. 确认号,占4个字节,是指望收到对方下一个报文的第一个数据字节的序号。例如,B收到了A发送过来的报文,其序列号字段是501,而数据长度是200字节,这代表B正确的收到了A发送的到序号700为止的数据。所以,B指望收到A的下一个数据序号是701,因而B在发送给A的确认报文段中把确认号置为701;
  4. 数据偏移,占4位,它指出TCP报文的数据距离TCP报文段的起始处有多远;
  5. 保留,占6位,保留从此使用,但目前应都位0;
  6. 紧急URG,当URG=1,代表紧急指针字段有效。告诉系统此报文段中有紧急数据;
  7. 确认ACK,仅当ACK=1时,确认号字段才有效。TCP规定,在链接创建后全部报文的传输都必须把ACK置1;
  8. 推送PSH,当两个应用进程进行交互式通讯时,有时在一端的应用进程但愿在键入一个命令后当即就能收到对方的响应,这时候就将PSH=1;
  9. 复位RST,当RST=1,代表TCP链接中出现严重差错,必须释放链接,而后再从新创建链接;
  10. 同步SYN,在链接创建时用来同步序号。当SYN=1,ACK=0,代表是链接请求报文,若赞成链接,则响应报文中应该使SYN=1,ACK=1;
  11. 终止FIN,用来释放链接。当FIN=1,代表此报文的发送方的数据已经发送完毕,而且要求释放;
  12. 窗口,占2字节,指的是通知接收方,发送本报文你须要有多大的空间来接受;
  13. 检验和,占2字节,校验首部和数据这两部分;
  14. 紧急指针,占2字节,指出本报文段中的紧急数据的字节数;
  15. 选项,长度可变,定义一些其余的可选的参数。

5、TCP链接的创建(三次握手)

120-TCP三次握手和四次挥手-三次握手.gif

  • 最开始的时候客户端和服务器都是处于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状态,此后双方就能够开始通讯了。

120-TCP三次握手和四次挥手-三次握手静态.jpg?x-oss-process=style/watermark

6、TCP四次挥手

120-TCP三次握手和四次挥手-四次挥手.gif

  • 数据传输完毕后,双方均可释放链接。最开始的时候,客户端和服务器都是处于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链接的时间要比客户端早一些。

120-TCP三次握手和四次挥手-四次挥手静态.png?x-oss-process=style/watermark

7、面试题

7.1 为何客户端最后还要等待2MSL?

MSL(Maximum Segment Lifetime),TCP容许不一样的实现能够设置不一样的MSL值。

  1. 保证客户端发送的最后一个ACK报文可以到达服务器,由于这个ACK报文可能丢失,站在服务器的角度看来,我已经发送了FIN+ACK报文请求断开了,客户端尚未给我回应,应该是我发送的请求断开报文它没有收到,因而服务器又会从新发送一次,而客户端就能在这个2MSL时间段内收到这个重传的报文,接着给出回应报文,而且会重启2MSL计时器。
  2. 防止相似与“三次握手”中提到了的“已经失效的链接请求报文段”出如今本链接中。客户端发送完最后一个确认报文后,在这个2MSL时间中,就可使本链接持续的时间内所产生的全部报文段都从网络中消失。这样新的链接中不会出现旧链接的请求报文。

7.2 为何创建链接是三次握手,关闭链接确是四次挥手呢?

创建链接的时候,服务器在LISTEN状态下,收到创建链接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。而关闭链接时,服务器收到对方的FIN报文时,仅仅表示对方再也不发送数据了可是还能接收数据,而本身也未必所有数据都发送给对方了,因此己方能够当即关闭,也能够发送一些数据给对方后,再发送FIN报文给对方来表示赞成如今关闭链接,所以,己方ACK和FIN通常都会分开发送,从而致使多了一次。

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

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

1、什么是Scoket

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

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

121-基于TCP协议的套接字编程-socket层.jpg?x-oss-process=style/watermark

  • 注意:也有人将socket说成ip+port,ip是用来标识互联网中的一台主机的位置,而port是用来标识这台机器上的一个应用程序,ip地址是配置到网卡上的,而port是应用程序开启的,ip与port的绑定就标识了互联网中独一无二的一个应用程序,而程序的pid是同一台机器上不一样进程或者线程的标识。

2、套接字发展史及分类

套接字起源于 20 世纪 70 年代加利福尼亚大学伯克利分校版本的 Unix,即人们所说的 BSD Unix。 所以,有时人们也把套接字称为“伯克利套接字”或“BSD 套接字”。一开始,套接字被设计用在同 一台主机上多个应用程序之间的通信。这也被称进程间通信,或 IPC。套接字有两种(或者称为有两个种族),分别是基于文件型的和基于网络型的。

2.1 基于文件类型的套接字家族

套接字家族的名字:AF_UNIX

unix一切皆文件,基于文件的套接字调用的就是底层的文件系统来取数据,两个套接字进程运行在同一机器,能够经过访问同一个文件系统间接完成通讯

2.2 基于网络类型的套接字家族

套接字家族的名字:AF_INET

(还有AF_INET6被用于ipv6,还有一些其余的地址家族,不过,他们要么是只用于某个平台,要么就是已经被废弃,或者是不多被使用,或者是根本没有实现,全部地址家族中,AF_INET是使用最普遍的一个,python支持不少种地址家族,可是因为咱们只关心网络编程,因此大部分时候我么只使用AF_INET)

3、套接字工做流程

一个生活中的场景。你要打电话给一个朋友,先拨号,朋友听到电话铃声后提起电话,这时你和你的朋友就创建起了链接,就能够讲话了。等交流结束,挂断电话结束这次交谈。 生活中的场景就解释了这工做原理。

121-基于TCP协议的套接字编程-socket流程.jpg?x-oss-process=style/watermark

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

import socket

# socket_family 能够是 AF_UNIX 或 AF_INET。socket_type 能够是 SOCK_STREAM 或 SOCK_DGRAM。protocol 通常不填,默认值为 0
socket.socket(socket_family, socket_type, protocal=0)

# 获取tcp/ip套接字
tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 获取udp/ip套接字
udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 因为 socket 模块中有太多的属性。咱们在这里破例使用了'from module import *'语句。使用 'from socket import *',咱们就把 socket 模块里的全部属性都带到咱们的命名空间里了,这样能大幅减短咱们的代码
tcpSock = socket(AF_INET, SOCK_STREAM)

121-基于TCP协议的套接字编程-小兵潮.gif

3.1 服务端套接字函数

方法 用途
s.bind() 绑定(主机,端口号)到套接字
s.listen() 开始TCP监听
s.accept() 被动接受TCP客户的链接,(阻塞式)等待链接的到来

3.2 客户端套接字函数

方法 用途
s.connect() 主动初始化TCP服务器链接
s.connect_ex() connect()函数的扩展版本,出错时返回出错码,而不是抛出异常

3.3 公共用途的套接字函数

方法 用途
s.recv() 接收TCP数据
s.send() 发送TCP数据(send在待发送数据量大于己端缓存区剩余空间时,数据丢失,不会发完)
s.sendall() 发送完整的TCP数据(本质就是循环调用send,sendall在待发送数据量大于己端缓存区剩余空间时,数据不丢失,循环调用send直到发完)
s.recvfrom() 接收UDP数据
s.sendto() 发送UDP数据
s.getpeername() 链接到当前套接字的远端的地址
s.getsockname() 当前套接字的地址
s.getsockopt() 返回指定套接字的参数
s.setsockopt() 设置指定套接字的参数
s.close() 关闭套接字

3.4 面向锁的套接字方法

方法 用途
s.setblocking() 设置套接字的阻塞与非阻塞模式
s.settimeout() 设置阻塞套接字操做的超时时间
s.gettimeout() 获得阻塞套接字操做的超时时间

3.5 面向文件的套接字的函数

方法 用途
s.fileno() 套接字的文件描述符
s.makefile() 建立一个与该套接字相关的文件

121-基于TCP协议的套接字编程-打电话.jpg?x-oss-process=style/watermark

4、基于TCP协议的套接字编程(简单)

  • 能够经过netstat -an | findstr 8080查看套接字状态

4.1 服务端

import socket

#一、买手机
phone = socket.socket(socket.AF_INET,
                      socket.SOCK_STREAM)  #tcp称为流式协议,udp称为数据报协议SOCK_DGRAM
# print(phone)

#二、插入/绑定手机卡
# 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())

# import time
# time.sleep(500)
#六、挂掉电话链接
conn.close()

#七、关机
phone.close()

4.2 客户端

import socket
# socket.AF
#一、买手机
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)

# import time
# time.sleep(500)
#四、关闭
phone.close()

5、基于TCP协议的套接字编程(循环)

5.1 服务端

import socket

#一、买手机
phone = socket.socket(socket.AF_INET,
                      socket.SOCK_STREAM)  #tcp称为流式协议,udp称为数据报协议SOCK_DGRAM
# print(phone)

#二、插入/绑定手机卡
# 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()

5.2 客户端1

import socket

#一、买手机
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# print(phone)
#二、拨电话
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()

5.3 客户端2

import socket

#一、买手机
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# print(phone)
#二、拨电话
phone.connect(('127.0.0.1', 8080))  # 指定服务端ip和端口

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

#四、关闭
phone.close()

6、地址占用问题

有的同窗在重启服务端时可能会遇到:

121-基于TCP协议的套接字编程-bug.png?x-oss-process=style/watermark

这个是因为你的服务端仍然存在四次挥手的time_wait状态在占用地址(若是不懂,请深刻研究1.tcp三次握手,四次挥手 2.syn洪水攻击 3.服务器高并发状况下会有大量的time_wait状态的优化方法)

6.1 方法一

# 加入一条socket配置,重用ip和端口

phone=socket(AF_INET,SOCK_STREAM)
phone.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #就是它,在bind前加
phone.bind(('127.0.0.1',8080))

6.2 方法二(Linux)

发现系统存在大量TIME_WAIT状态的链接,经过调整linux内核参数解决,
vi /etc/sysctl.conf

编辑文件,加入如下内容:
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30
 
而后执行 /sbin/sysctl -p 让参数生效。
 
net.ipv4.tcp_syncookies = 1 表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少许SYN攻击,默认为0,表示关闭;

net.ipv4.tcp_tw_reuse = 1 表示开启重用。容许将TIME-WAIT sockets从新用于新的TCP链接,默认为0,表示关闭;

net.ipv4.tcp_tw_recycle = 1 表示开启TCP链接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。

net.ipv4.tcp_fin_timeout 修改系統默认的 TIMEOUT 时间
相关文章
相关标签/搜索