python网络-Socket之TCP编程(26)

1、TCP简介

一、TCP介绍数据库

TCP协议,传输控制协议(英语:Transmission Control Protocol,缩写为 TCP)是一种面向链接的、可靠的、基于字节流的传输层通讯协议。编程

TCP通讯须要通过建立链接、数据传送、终止链接三个步骤。后端

TCP通讯模型中,在通讯开始以前,必定要先创建相关的连接,才能发送数据,相似于生活中,"打电话"。服务器

二、TCP面向链接网络

通讯双方必须先创建链接才能进行数据的传输,双方都必须为该链接分配必要的系统内核资源,以管理链接的状态和链接上的传输。并发

双方间的数据传输均可以经过这一个链接进行。socket

完成数据交换后,双方必须断开此链接,以释放系统资源。tcp

这种链接是一对一的,所以TCP不适用于广播的应用程序,基于广播的应用程序请使用UDP协议。函数

三、TCP可靠传输网站

1)TCP采用发送应答机制

TCP发送的每一个报文段都必须获得接收方的应答才认为这个TCP报文段传输成功

2)超时重传

发送端发出一个报文段以后就启动定时器,若是在定时时间内没有收到应答就从新发送这个报文段。TCP为了保证不发生丢包,就给每一个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。而后接收端实体对已成功收到的包发回一个相应的确认(ACK);若是发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据包就被假设为已丢失将会被进行重传。

3)错误校验

TCP用一个校验和函数来检验数据是否有错误;在发送和接收时都要计算校验和。

4) 流量控制和阻塞管理

流量控制用来避免主机发送得过快而使接收方来不及彻底收下。

四、TCP与UDP的不一样点

  • 面向链接(确认有建立三方交握,链接已建立才做传输。)
  • 有序数据传输
  • 重发丢失的数据包
  • 舍弃重复的数据包
  • 无差错的数据传输
  • 阻塞/流量控制

 

2、TCP数据包格式

所谓三次握手(Three-way Handshake),是指创建一个TCP链接时,须要客户端和服务器总共发送3个数据包

那么咱们就先来看一下TCP数据包的格式:

 

在TCP层,有个FLAGS字段,这个字段有如下几个标识:SYN, FIN, ACK, PSH, RST, URG.
  • URG—为1表示高优先级数据包,紧急指针字段有效。
  • ACK—为1表示确认号字段有效
  • PSH—为1表示是带有PUSH标志的数据,指示接收方应该尽快将这个报文段交给应用层而不用等待缓冲区装满。
  • RST—为1表示出现严重差错。可能须要重现建立TCP链接。还能够用于拒绝非法的报文段和拒绝链接请求。
  • SYN—为1表示这是链接请求或是链接接受请求,用于建立链接和使顺序号同步
  • FIN—为1表示发送方没有数据要传输了,要求释放链接
  • Seq---序号,这是为了链接之后传送数据用的,
  • Ack---确认号对收到的数据包的确认,值是等待接收的数据包的序列号+1。

 

3、TCP的三次握手

三次握手的目的是链接服务器指定端口,创建TCP链接,并同步链接双方的序列号和确认号并交换 TCP 窗口大小信息.在socket编程中,客户端执行connect()时。将触发三次握手。

三次握手示意图

第一次握手:(Client向Server发送联机请求)

SYN=1(Client向Server发送联机请求)

Client想要与Server进行TCP通讯,首先他须要向Server发送一个SYN=1的同步序列编号(syncsynchronized squsequence number)用来表示创建链接,而且随机产生一个数Seq number = X的数据包到Server,Server因为SYN=1知道,Client要求创建联机,到这里第一次握手就结束了

第二次握手:(Server向Client回复联机并确认联机信息)

SYN=1(Server接受Client的联机请求)

ACK=1(确认信息)

这是对第一次握手信息的确认,表示Server收到了Client的第一次握手信息

Ack=X+1(确认回复)

同时Server回复Client一个确认码Ack表示你的联机请求我已经收到,并且数据没有丢失,怎么验证数据没有丢失呢?即Ack的值等于Client发过来Seq的值加1,即Ack = X+1。由于我都知道你发过来的Seq的值,因此这个数据包没有丢失。

Seq = Y(第二次握手的数据包序列号)

Server给Client的数据包序列号,为了数据包在到达Client以后的验证,因此此次从Server到Client的数据包中一样也会随机产生一个Seq number = Y,

第三次握手

ACK=1(对第二次握手的确认)

首先Client会打开Server发送过来的Ack验证一下是否正确为Seq+1,即第一次发送的seq number+1,确认无误后,Client仍然须要给Server再次回复确认即ACK=1

Seq=Z(第三次握手的数据包序列号)

Ack=Y+1

Client告诉Server,你给我回复的信息我也收到了,怎么肯定我收到了你的信息呢?就是经过Ack等于第二次握手传递过来的Seq值+1。到此为止三次握手结束进入ESTABLISHED状态,开始进行数据传输。

 

4、TCP四次挥手

 

第一次挥手发送FIN请求,第一次挥手结束。

第二次挥手开始,被动方向主动方发送ACK确认码,到这里第二次挥手结束。

第三次握手开始被动方向主动方发送FIN号结束。

第四次挥手开始主动方向被动方发送ACK确认,等待2MSL后断开TCP链接。

 

5、TCP的十种状态

这十种状态分别是三次握手和四次挥手中的状态,在上面两个图中都给你们标记出来了,这里再给你们一个简单的图表示

 

6、TCP的2MSL问题

在四次挥手中咱们提到了时间等待状态,等待的时间是2MSL。

2MSL即两倍的MSL,TCP的TIME_WAIT状态也称为2MSL等待状态,

当TCP的一端发起主动关闭,在发出最后一个ACK包后,即第3次挥手完成后发送了第四次挥手的ACK包后就进入了TIME_WAIT状态,必须在此状态上停留两倍的MSL时间,等待2MSL时间主要目的是怕最后一个 ACK包对方没收到,那么对方在超时后将重发第三次挥手的FIN包,主动关闭端接到重发的FIN包后能够再发一个ACK应答包。在TIME_WAIT状态时两端的端口不能使用,要等到2MSL时间结束才可继续使用。当链接处于2MSL等待阶段时任何迟到的报文段都将被丢弃。不过在实际应用中能够经过设置 SO_REUSEADDR选项达到没必要等待2MSL时间结束再使用此端口。

 

7、TCP长链接和短链接

TCP在真正的读写操做以前,server与client之间必须创建一个链接,

当读写操做完成后,双方再也不须要这个链接时它们能够释放这个链接,

链接的创建经过三次握手,释放则须要四次握手,

因此说每一个链接的创建都是须要资源消耗和时间消耗的。

1. TCP短链接

模拟一种TCP短链接的状况:

  1. client 向 server 发起链接请求
  2. server 接到请求,双方创建链接
  3. client 向 server 发送消息
  4. server 回应 client
  5. 一次读写完成,此时双方任何一个均可以发起 close 操做

在第 步骤5中,通常都是 client 先发起 close 操做。固然也不排除有特殊的状况。从上面的描述看,短链接通常只会在 client/server 间传递一次读写操做!

2. TCP长链接

再模拟一种长链接的状况:

  1. client 向 server 发起链接
  2. server 接到请求,双方创建链接
  3. client 向 server 发送消息
  4. server 回应 client
  5. 一次读写完成,链接不关闭
  6. 后续读写操做...
  7. 长时间操做以后client发起关闭请求

3. TCP长/短链接操做过程

(1)短链接的操做步骤是:创建链接——数据传输——关闭链接...创建链接——数据传输——关闭链接

(2) 长链接的操做步骤是:创建链接——数据传输...(保持链接)...数据传输——关闭链接

4. TCP长/短链接的优势和缺点

  • 长链接能够省去较多的TCP创建和关闭的操做,减小浪费,节约时间。对于频繁请求资源的客户来讲,较适用长链接。

  • client与server之间的链接若是一直不关闭的话,会存在一个问题,随着客户端链接愈来愈多,server迟早有扛不住的时候,这时候server端须要采起一些策略,如关闭一些长时间没有读写事件发生的链接,这样能够避免一些恶意链接致使server端服务受损;若是条件再容许就能够以客户端机器为颗粒度,限制每一个客户端的最大长链接数,这样能够彻底避免某个蛋疼的客户端连累后端服务。

  • 短链接对于服务器来讲管理较为简单,存在的链接都是有用的链接,不须要额外的控制手段。但若是客户请求频繁,将在TCP的创建和关闭操做上浪费时间和带宽。

5. TCP长/短链接的应用场景

  • 长链接多用于操做频繁,点对点的通信,并且链接数不能太多状况。每一个TCP链接都须要三次握手,这须要时间,若是每一个操做都是先链接,再操做的话那么处理速度会下降不少,因此每一个操做完后都不断开,再次处理时直接发送数据包就OK了,不用创建TCP链接。

    例如:数据库的链接用长链接,若是用短链接频繁的通讯会形成socket错误,并且频繁的socket 建立也是对资源的浪费。

  • 而像WEB网站的http服务通常都用短连接,由于长链接对于服务端来讲会耗费必定的资源,而像WEB网站这么频繁的成千上万甚至上亿客户端的链接用短链接会更省一些资源,若是用长链接,并且同时有成千上万的用户,若是每一个用户都占用一个链接的话,那可想而知吧。因此并发量大,但每一个用户无需频繁操做状况下需用短连好。

 

8、TCP的通讯模型

tcp通讯模型中,在通讯开始以前,必定要先创建相关的连接,才能发送数据,相似于生活中,"打电话"

生活中的电话机,若是想让别人能更够打通我们的电话获取相应服务的话,须要作一下几件事情:

  1. 买个手机
  2. 插上手机卡
  3. 设计手机为正常接听状态(即可以响铃)
  4. 静静的等着别人拨打

tcp服务器如同上面的电话机过程同样,在程序中,若是想要完成一个tcp服务器的功能,须要的流程以下:

  1. 建立一个socket套接字
  2. bind绑定ip和port
  3. listen使套接字变为能够被动连接
  4. accept等待客户端的连接
  5. recv/send接收发送数据

 

9、TCP服务器代码实现

#coding = utf-8
from socket import *
#一、建立socket套接字
tcpServerSocket = socket(AF_INET,SOCK_STREAM)
#二、绑定本地信息
address = ("",7788)
tcpServerSocket.bind(address)
#三、使用socket建立的套接字默认的属性是主动的,使用listen将其变为被动,这样就能够等着别人连接了
tcpServerSocket.listen(5)

"""
若是有新的客户端来连接服务器,那么就产生一个新的套接字专门为这个客户端服务器
newSocket用来为这个客户端服务
tcpServerSocket就能够省下来专门等待其余的客户端的连接
"""
newSocket,clientAddress = tcpServerSocket.accept()

#四、接收对象发送过来的数据,最大接收1024个字节
reveiveData = newSocket.recv(1024)
print("接收的数据为:%s"%reveiveData.decode())

#五、发送数据到客户端
newSocket.send("haha".encode())

#六、关闭为这个客户端服务的套接字
newSocket.close()

#七、关闭监听套接字
tcpServerSocket.close()

运行流程

一、TCP服务器

二、网络调试助手:

 

10、TCP客户端代码实现

所谓的服务器端:就是提供服务的一方,而客户端,就是须要被服务的一方

tcp的客户端要比服务器端简单不少,若是说服务器端是须要本身买手机、查手机卡、设置铃声、等待别人打电话流程的话,那么客户端就只须要找一个电话亭,拿起电话拨打便可,流程要少不少

#coding = utf-8
from socket import *

#一、建立socket
tcpClientSocket = socket(AF_INET,SOCK_STREAM)

#二、连接服务器
serverAddress = ("192.168.100.106",7788)
tcpClientSocket.connect(serverAddress)

#三、向服务器发送数据
tcpClientSocket.send("哈哈".encode("gb2312"))

#四、接收对方发送过来的数据,最大接收1024个字节
receiveData = tcpClientSocket.recv(1024)
print("接收到的数据为%s"%receiveData.decode("gb2312"))

#五、关闭套接字
tcpClientSocket.close()

运行流程:

一、tcp客户端

二、网络调试助手:

相关文章
相关标签/搜索