上海服装网站建设,武进网站建设基本流程,百度热搜榜在哪里看,seo网站优化优化排名6. TCP 三次握手四次挥手
HTTP 协议是 Hype Transfer Protocol#xff08;超文本传输协议#xff09;的缩写#xff0c;是用于从万维网#xff08;WWW#xff1a;World Wide Web#xff09;服务器#xff08;sever#xff09;传输超文本到客户端#xff08;本地浏览器…6. TCP 三次握手四次挥手
HTTP 协议是 Hype Transfer Protocol超文本传输协议的缩写是用于从万维网WWWWorld Wide Web服务器sever传输超文本到客户端本地浏览器 client的传送协议。HTTP 协议基于 TCP/IP 协议之上HTTPS 基于 TLS/SSL 协议层上两者都是属于应用层的面向对象的协议。 由上图可知HTTP 协议工作前需要 client 与 sever 建立连接。该连接由 tcp 来完成tcp 与 ip 共同组成了 Internet也就是著名的 TCP/IP 通信协议。
6.1 TCP 简介
TCPTransmission Control Protocol全名传输控制协议是主机对住几层的传输控制协议提供可靠的连接服务采用三次握手来建立一个连接。与 UDP 都是传输层的协议比 UDP 更可靠默认端口 80 。
TCP标志位位码
SYNsynchronous建立连接ACKacknowledgement确认ack确认号PSHpush传送FINfinish结束RSTreset重置URGurgent紧急Sequence number顺序号码Acknowledge number确认号码
6.2 三次握手 最初两端 TCP 进程都处于关闭状态client 主动打开连接server 被动打开连接。大致步骤client、server 关闭 —— server 收听到 listen —— client 同步已发送状态 SYN-SENT —— server 同步收到状态 SYN_RCVD —— client、server 已建立状态 ESTABLEISHED。
规定SYN1 的报文不传输数据并消耗一个随机序列号。
1、第一次
client 向 server 发送连接请求报文 SYN1 同时生成初始序列化 seqx此时 client 进入 SYN-SENT同步已发送状态。
2、第二次
server 收到请求报文后如果同意连接则发出确认报文。确认报文中包含ACK1SYN1确认号ackx1即上一次的seq1同时也要为自己随机初始化一个序列号 seqy。此时 server 进入 SYN-RCVD同步收到状态。这个报文也没有携带数据循环 client 是否准备好。
3、第三次
client 收到确认后向 server 给出确认ACK1与 server 给出的一致acky1此时 client 连接建立进入 ESTABLISHED 状态。这里客户端表示已经准备好了。
6.3 四次挥手 1、第一次
client 发送一个 FIN 用来结束连接。client 进程发出连接释放报文并停止发送数据。释放报文首部FIN1序列号 seqi。
此时 client 进入 FIN_WAIT_1 终止等待1状态。
2、第二次
server 收到这个 FIN 后返回一个 ACK确认确认序号acki1。同时携带自己的序列号 seqj。
此时 server 进入 CLOSED_WAIT关闭等待状态。
并通知高层的应用进程此时处于半关闭状态client 没有数据发送了但 server 若发送数据client 依然会接收这种状态还会持续一段时间。
3、第三次
server 将最后的数据发送完毕后发送一个 FIN结束确认序号acki1同时携带序号 seqw准备 关闭 client 的连接等待 client 的最后确认。
此时server 进入 LAST_ACK最后确认状态。
4、第四次
client 发送 ACK 确认并将确认序号1ackw1而自己序列号 seqi1。
此时client 进入 TIME_WAIT时间等待状态。 **Note**此时 client 并没有释放必须等待 2MSL最长报文段寿命使君子后当 server 撤销相应 TCB 后从进入 CLOSED 状态。server 只要收到了 client 发出的确认立即进入CLOSED状态。同样撤销TCB后就结束了这次的TCP连接 为什么会是四次挥手
三次握手时没有数据传输而四次挥手时涉及到有数据传输。client 发出关闭请求表示已经数据传输完毕但是 server 有可能数据还未传输完毕这时就需要已 server 端数据是否传输完毕为标准因此需要四次。
当高并发时现实情况往往是 server 先断开 client 连接因为多保存 client 一次连接就会多占用一些资源。因此在短时间内再次向 server 发起连接会提示 serve time_wait。
客户端突然挂掉了怎么办
正常连接时客户端突然挂掉了如果没有措施处理这种情况那么就会出现客户端和服务器端出现长时期的空闲。解决办法是在服务器端设置保活计时器每当服务器收到
客户端的消息就将计时器复位。超时时间通常设置为2小时。若服务器超过2小时没收到客户的信息他就发送探测报文段。若发送了10个探测报文段每一个相隔75秒
还没有响应就认为客户端出了故障因而终止该连接。
参考文章https://www.cnblogs.com/qdhxhz/p/8470997.html
7. 客户端服务端循环发送信息
之前设计的 socket 程序只能进行一次发送接收就终止掉了而现实情况不可能只有一次发送与接收往往都是循环往复那么就需要给 socket client 和 socket server 添加循环机制。
服务端
from socket import *ip_port (127.0.0.1, 8000)
back_log 5
buffer_size 1024tcp_server socket(AF_INET, SOCK_STREAM)
tcp_server.bind(ip_port)
tcp_server.listen(back_log)print(服务端开始运行)
conn, addr tcp_server.accept()while True:data conn.recv(buffer_size)print(客户端发来的信息是, data.decode(utf-8))conn.send(data.upper())conn.close()
tcp_server.close()服务端开始运行
客户端发来的信息是 python客户端
from socket import *ip_port (127.0.0.1, 8000)
buffer_size 1024tcp_client socket(AF_INET, SOCK_STREAM)
tcp_client.connect(ip_port) # 连接服务端while True:msg input(请输入要发送的信息)tcp_client.send(msg.encode(utf-8))print(---------客户端已经发送消息------------)data tcp_client.recv(buffer_size)print(接收到服务端发来的信息, data.decode(utf-8))tcp_client.close()请输入要发送的信息python
---------客户端已经发送消息------------
接收到服务端发来的信息 PYTHON
请输入要发送的信息8. socket 收发信息原理剖析
socket 客户端和服务端都属于应用层即用户态层面。它们产生的数据或从客户端发送到服务端的数据必须通过内核态调用操作系统将数据 copy 到内存中缓存然后根据 TCP/UDP 协议、通过网卡、Internet 传输到服务端。
服务端再通过内核态从缓存中取出数据。收发消息会在缓存中形成一个消息队列遵循 先进先出原则后面进来的消息后处理。 操作系统的体系架构分为 用户态和内核态内核从本质上讲也一种软件 —— 控制计算机的硬件资源并提供上层应用程序运行的环境。
用户态即上层应用程序的活动空间应用程序的执行必须依托内核提供的资源包括CPU、存储、I/O资源等。为了使用户态能访问这些资源内核必须为上层应用提供访问的接口 —— 系统调用系统调用是操作系统的最小单位。
9. 服务端循环连接请求来接收信息
9.1 当用户输入为空或直接回车时
当用户在 client 端输入为空或直接输入回车时client 端与 server 端都开在接收信息处。这是因为 client 端没有真正的信息0 字节发送给 server 端因此 server 端就不会有信息回复。 解决办法在 client 端对用户输入的信息进行判断即可 if not msg:continue # 如果输入信息为空那么继续输入9.2 当 client 端异常断开时
当我们直接断开 client 的连接而非四次挥手时正常断开发现 server 直接报如下错误
ConnectionResetError: [WinError 10054] 远程主机强迫关闭了一个现有的连接。现实情况中不可能一个 client 端每次不正常断开连接就导致 server 端直接断开。那么其他的 client 就不能连接 server。 解决办法对 server 端信息接收处使用异常处理 while True:try:data conn.recv(buffer_size)print(客户端发来的信息是, data.decode(utf-8))conn.send(data.upper())except Exception:break这样不论 client 端是怎么断开的都不会导致 server 端断开。
9.3 当有多个 client 发起连接时
当有多个 client 发起连接时遵循 先进先出 原则。先连接的 client 先处理后发起连接的 client 会被存储到 back_log 中。back_log 为链接监听listen的最大数目。
每次只能处理一天连接当处理完毕后就会直接关闭连接也就是说只能服务一个 client我们希望的是 server 端能够循环提供服务显然这不是我们想要的结果。 解决办法对被动接受 client 的连接处进行循环即 accept 服务端
from socket import *# 获取主机名
host gethostname()
# 端口号
port 8080back_log 5
buffer_size 1024tcp_server socket(AF_INET, SOCK_STREAM)
tcp_server.bind((host, port))
tcp_server.listen(back_log)while True: # 循环接收 client 发起的连接print(服务端开始运行)print(host)conn, addr tcp_server.accept()while True: # 循环接收 client 发来的信息以及发送信息给 client try: # 对 client 的异常断开进行异常处理data conn.recv(buffer_size)print(客户端发来的信息是, data.decode(utf-8))conn.send(data.upper())except Exception:breakconn.close()
tcp_server.close()客户端
from socket import *# 获取主机名
host gethostname()
# 端口号
port 8080buffer_size 1024tcp_client socket(AF_INET, SOCK_STREAM)
tcp_client.connect((host, port)) # 连接服务端while True:msg input(请输入要发送的信息).strip()if not msg: continue # 对用户输入的信息进行判断tcp_client.send(msg.encode(utf-8))print(---------客户端已经发送消息------------)data tcp_client.recv(buffer_size)print(接收到服务端发来的信息, data.decode(utf-8))tcp_client.close()9.5 总结
要想 client 与 server 能够自由交互数据并且 server 能循环提供服务需要满足如下条件
需要对用户输入的数据进行判断server 能够处理 client 异常断开时的情况server 要能够循环接收 client 发起的连接
10. socket 函数
1. 服务端套接字函数
s.bind()绑定主机端口号到套接字元组形式s.listen()开始 TCP 监听s.accept()被动接受 TCP 客户的连接阻塞式等待连接的到来。
2. 客户端套接字函数
s.connect()主动初始化 TCP 服务器连接s.connect_ex()connect函数的拓展版本出错时返回出错码而不是抛出异常
3. 公共用途套接字函数
s.recv()接受 TCP 数据s.send()发送 TCP 数据send 在待发送数据量大于己端缓存区剩余空间时数据丢失不会发完s.sendall()发送完整的 TCP 数据本质就是循环调用 sendsendall 在待发送数据量大于己端缓存区剩余空间时数据不丢失循环调用 send 直到发完。s.recvfrom()接收 UDP 数据s.sendto()发送 UDP数据s.getpeername()连接到当前套接字的远端的地址s.getsockname()当前套接字的地址s.getsockopt()返回指定套接字的参数s.setsockopt()设置指定套接字的参数s.close()关闭套接字
面向锁的套接字函数
s.setblocking()设置套接字的阻塞与非阻塞模式s.settimeout()设置阻塞套接字操作的超时时间s.gettimeout()得到阻塞套接字操作的超时时间
面向文件的套接字的函数
s.fileno()套接字的文件描述符s.makefile()创建一个与该套接字相关的文件 **Tips**send 一次最大数据最好控制在 8 k 左右为了避免超过内存大小可以使用 sendall 方法。其本质是在循环调用 send 方法。