Python 复习笔记 WEB服务器(TCP的三次握手和四次挥手)
WEB服务器:
1.短连接与长连接:
1.短连接就是用三次 ‘握手挥手’ 获得三次数据。-------如果是处理一些比较小的数据,就用短连接,客户一连接,就给他数据然后断开连接,腾出资源。
2.长连接就是用一次 ‘握手挥手’ 获得三次数据。-------如果处理的是长时间的数据,就用长连接,但会监听客户端的数据,如果在一段时间没有收到客户端的数据,就会断开连接,腾出资源给其他人。
假如访问一个网站,网站上有许多图片:
1.如果是短连接:它会先连接,获得网站数据,然后为在数据中得到的每个图片发起一次连接,最后显示返回的图片数据 。
# 这样会创建多个套接字,然后会创建多个进程、线程、协程来处理套接字。
2.如果是长连接,它会先连接,获得网站数据,但不断开,继续访问每个图片的数据,显示返回的图片数据。
短连接传完了就调用close 但是长连接不调用,客户端必须让服务器知道你接受完毕才会重新接受客户端的数据。
因此服务器在给客户端传数据的时候,数据头中有 content-Length: xx 来表示发送了多少的数据。
2.epoll的两个特点
1.内存映射:
* 内存映射* 一台电脑有应用程序和操作系统两个的各自使用空间,两者是绝对分开的。每次执行都要把信息从应用程序空间拷贝到操作系统空间去执行,但使用单线程非堵塞的话,会创建一个列表,而操作系统是每个程序都执行一点的雨露均沾型,所以如果一个列表太大,而拷贝信息也要时间,那么运行速度会变慢。
而epoll会创建一个空间,是应用程序和操作系统共用的空间,这样就不要拷贝就能直接得到信息了。(感觉跟Queue队列差不多)
2.时间通知:
使用的是时间通知(当可以接收的数据到来时,通知可以接收数据的对线来接收)而不是轮询(每个询问一遍:有没有数据要接收)
3.TCP-IP协议:
TCP-IP协议不是一个协议,是一类协议,是许多协议的总称。因为每个协议的目的不同
4.OSI协议
5.网络通讯(电脑之间的通信)
在电脑通信之前,必须规定好 IP 和 子网掩码 才能进行通信
通信方式的发展:
1.集线器:
网线与电线不同,电线可以从中间接条导线出来使用,网线不能这样连接多台电脑,所以就有了 集线器(Hub)(很久以前的方法)
缺点:使用广播的方式发送数据,即:A给B发送数据,集线器会与ABCD都建立连接,如果这时C想给D发送数据就不行,因为通道被占用了
2.交换器:
1.克服了集线器以广播发送数据的缺点,当需要广播的时候发送广播,当需要单播的时候又能够以单播的方式进行发送
2.企业中就是用交换器来完成多台电脑的网络连接的,代替了之前的集线器
3.但是交换器不止需要 IP和端口,而且需要知道MAC地址。
但是平常发送文件的时候都不询问MAC地址,为什么能直接发送?
这是因为,当你发送数据时,交换器会广播所有电脑,并用ARP的方式发送一个所有电脑都能接收的MAC地址:FF:FF:FF:FF:FF:FF,并且带有源IP和目的IP,目的IP就会把自己的MAC地址返回到源IP电脑中,最后发送方就会使用目的IP、目的端口和目的MAC地址发送数据
3.路由器:
1.如果想给不同网络号的电脑发送数据,自己不能发送就要找一个有能力的设备代理,那就是网关(一般是路由器)
2.第一次发送要有目的IP、目的MAC(网关的MAC,也就是路由器的MAC)、源IP和源MAC;到网关后,网关会把目的MAC改成对方路由器的MAC地址(右边路由器),对方路由器再把MAC地址改成目的IP的MAC地址(IP地址不变但MAC地址一直在变)
4.输入域名访问服务器:
1.输入域名,然后浏览器会访问DNS服务器(就跟一个电话本一样)来解析域名:
1.用ARP广播的方式得到默认网关的地址
2.DNS服务器的IP地址是固定的,但不是同一个网络号,所以先要把数据发送到默认网关(跟上面的路由器通信类似)
3.因为IP地址的范围是划分好的,所以默认网关知道DNS服务器在哪
4.DNS服务器把解析出来的IP地址返回给默认网关,默认网关把IP地址返回给本机
2.把域名解析成IPD地址后,浏览器向目的服务器发起tcp的三次握手
3.三次握手成功后,会发送HTTP协议的数据 "POST/GET HTTP1.1"等数据包内容,然后等待服务器的应答
4.最后发送tcp的四次挥手,断开通路
6.TCP的3次握手和4次挥手
开始连接:(3次握手) 准备资源
TCP通信时 客户端connect服务器就是三次握手
1.客户端准备好了,想告诉服务端让他也准备好,所以发送了一个值SYN=11
2.服务端准备好了,想告诉客户端端他准备好了,所以发送了一个值ACK=SYN+1=11+1=12
3.服务端想知道客户端是不是真的准备好了,就发送了一个值 SYN = 22
4.客户端告诉服务端,自己真的准备好了,把ACK=SYN+1=22+1=23 发送给 服务端
由于2、3都是服务端发送数据给客户端,所以两个数据可以一起发送,就只有3次握手
发送内容:
发送内容后,服务端都会偷偷告诉你,已经收到内容了(ACK)
结束连接:(4次挥手) 释放资源
因为套接字是全双工的,所以结束连接时客户端和服务端的'收/发'两个通道都要关闭
1.客户端调用close 客户端关闭'发送'通道,告诉服务器不会再给他发送信息了
2.服务端说知道了,关闭'接收'通道
3.服务端调用close 服务端关闭'发送'通道,告诉客户端我也不会给他发送消息了
4.客户端说知道了,关闭'接收'通道
问题:
1.为什么开始时四次可以变成三次,结束时却不行呢?
如果2.3 合在一起:'2'是为了告诉客户端已经接收到数据了,如果服务端暂时不想调用close,那么'3'不就不能发送了,如果2.3连在一起就出现问题了
所以2应该先发送,这样客户端就可以先释放资源了
2.为什么是客户端先关闭释放资源呢?
因为TCP如果收到对方消息一般都会发送ACK代表已经收到,(一个发送,一个说收到你的发送,一个再说收到你发送的收)这样到最后不就无限重复了
所以谁(服务端)最后调用close,就会设置超时时间,如果没收到(客户端)应答就会一直发请求,万一客户端的内容丢失或这发送失败,就会导致服务端没有收到应答,这样服务端就会再发送一次请求,如果这时候客户端的资源已经释放,就没有内容给服务端了,所以客户端发送应答后会等待一段时间(2MSL 两倍的数据包传送时间 来回)
所以谁先发起close 谁的资源就要保留两分钟,这样客户端的端口在这两分钟保留期间即使被占用了,下次连接也是随机端口,而服务端是绑定端口的就会出现问题
解决方法:
tcp_server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
# 这样服务端即使先调用close,资源也会被立刻释放