网络编程(二)

news2024/9/20 20:33:57

6. TCP 三次握手四次挥手

HTTP 协议是 Hype Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web)服务器(sever)传输超文本到客户端(本地浏览器 client)的传送协议。HTTP 协议基于 TCP/IP 协议之上,HTTPS 基于 TLS/SSL 协议层上,两者都是属于应用层的面向对象的协议。

由上图可知,HTTP 协议工作前需要 client 与 sever 建立连接。该连接由 tcp 来完成,tcp 与 ip 共同组成了 Internet,也就是著名的 TCP/IP 通信协议。

6.1 TCP 简介

TCP(Transmission Control Protocol)全名传输控制协议,是主机对住几层的传输控制协议,提供可靠的连接服务,采用三次握手来建立一个连接。与 UDP 都是传输层的协议,比 UDP 更可靠,默认端口 80 。

TCP标志位(位码):

  • SYN(synchronous):建立连接
  • ACK(acknowledgement):确认
  • ack:确认号
  • PSH(push):传送
  • FIN(finish):结束
  • RST(reset):重置
  • URG(urgent):紧急
  • Sequence number:顺序号码
  • Acknowledge number:确认号码

6.2 三次握手

最初两端 TCP 进程都处于关闭状态,client 主动打开连接,server 被动打开连接。大致步骤:client、server 关闭 —— server 收听到 listen —— client 同步已发送状态 SYN-SENT —— server 同步收到状态 SYN_RCVD —— client、server 已建立状态 ESTABLEISHED。

规定:SYN=1 的报文不传输数据,并消耗一个随机序列号。

1、第一次

client 向 server 发送连接请求报文 SYN=1 ,同时生成初始序列化 seq=x,此时 client 进入 SYN-SENT(同步已发送)状态。

2、第二次

server 收到请求报文后,如果同意连接,则发出确认报文。确认报文中包含:ACK=1,SYN=1,确认号:ack=x+1(即上一次的seq+1),同时也要为自己随机初始化一个序列号 seq=y。此时 server 进入 SYN-RCVD(同步收到)状态。这个报文也没有携带数据,循环 client 是否准备好。

3、第三次

client 收到确认后,向 server 给出确认:ACK=1(与 server 给出的一致),ack=y+1,此时 client 连接建立,进入 ESTABLISHED 状态。这里客户端表示已经准备好了。

6.3 四次挥手

1、第一次

client 发送一个 FIN ,用来结束连接。client 进程发出连接释放报文,并停止发送数据。释放报文首部:FIN=1,序列号 seq=i

此时 client 进入 FIN_WAIT_1 (终止等待1)状态。

2、第二次

server 收到这个 FIN 后,返回一个 ACK(确认),确认序号:ack=i+1。同时携带自己的序列号 seq=j

此时, server 进入 CLOSED_WAIT(关闭等待)状态。

并通知高层的应用进程,此时处于半关闭状态,client 没有数据发送了,但 server 若发送数据,client 依然会接收,这种状态还会持续一段时间。

3、第三次

server 将最后的数据发送完毕后,发送一个 FIN(结束),确认序号:ack=i+1,同时携带序号 seq=w,准备 关闭 client 的连接,等待 client 的最后确认。

此时,server 进入 LAST_ACK(最后确认)状态。

4、第四次

client 发送 ACK 确认,并将确认序号+1:ack=w+1,而自己序列号 seq=i+1

此时,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 = 1024

tcp_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 = 1024

tcp_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 = 8080

back_log = 5
buffer_size = 1024


tcp_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:
            break

    conn.close()
tcp_server.close()

客户端:

from socket import *

# 获取主机名
host = gethostname()
# 端口号
port = 8080

buffer_size = 1024

tcp_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 数据(本质就是循环调用 send,sendall 在待发送数据量大于己端缓存区剩余空间时,数据不丢失,循环调用 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 方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/391726.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

小众但意外觉得蛮好用的剪辑软件!纯良心分享

爱剪辑 有开屏广告,一共3个界面:首页、剪同款、我的。 剪辑、配乐、字幕、滤镜、加速、贴纸、配音等主流功能都有。 特色功能有剪裁视频、倒放视频、视频旋转、视频转换GIF、转场、提取音频、画中画等。 还可以拼接视频,不过不支持FLV等小众文…

人员摔倒识别预警系统 人员跌倒检测算法 yolov7

人员摔倒识别预警系统 人员跌倒检测算法基于yolov7网络模型计算机识别技术,人员摔倒识别预警系统 人员跌倒检测算法对画面中人员摔倒进行实时检测识别抓拍告警。YOLOv7 的策略是使用组卷积来扩展计算块的通道和基数。研究者将对计算层的所有计算块应用相同的组参数和…

buuctf-pwn write-ups (11)

文章目录buu083-x_ctf_b0verfl0wbuu084-picoctf_2018_leak_mebuu085-inndy_echobuu086-hitcontraining_unlinkbuu087-ciscn_2019_final_3buu088-axb_2019_fmt64buu089-wustctf2020_name_your_catbuu090-pwnme1buu091-axb_2019_brop64buu092-[极客大挑战 2019]Not Badbuu083-x_c…

JAVA开发运维(nginx工作原理)

nginx源码目录结构: . ├── auto 自动检测系统环境以及编译相关的脚本 │ ├── cc 关于编译器相关的编译选项的检测脚本 │ ├── lib nginx编译所需要的一些库的检测脚本 │ ├── os 与平台相关的一些系统参数…

2023-03-06 debian11 最小安装记录

1.镜像准备,根据个人需求下载debian 版本Debian -- 获取 Debian2.上传到VSAN 内容库我这边是在vm里面安装的,就直接上传到内容库备用(根据个人需求存放)3.分配虚拟主机配置根据个人需要配置4.开始最小安装1.在界面中选择Install&a…

Packet Tracer--配置帧中继

Packet Tracer--配置帧中继 拓扑图: 设备参数: 设备 接口 DLCI R1 S0/2 102,103 R2 S0/2 201 R3 S0/2 301 R1---R2 Se1:102-----Se2:201 R1---R3 Se1:103-----Se3:301 IP参数 设备 接口 IP地址…

CFNet: Cascade Fusion Network for Dense Prediction

论文名称:CFNet: Cascade Fusion Network for Dense Prediction 论文下载:https://arxiv.org/pdf/2302.06052.pdf 论文代码:GitHub - zhanggang001/CFNet: CFNet: Cascade Fusion Network for Dense Prediction 摘要: 在密集预…

十四届蓝桥选拔赛Scratch-2023.02.12 试题解析

十四届蓝桥选拔赛Scratch-2023.02.12 试题解析 单选题: 1. 运行以下程序,小猫和小企鹅谁能到达舞台右侧边缘? ( B ) *选择题严禁使用程序验证,选择题不答和答错不扣分 A. 小企鹅 B. 小猫 C. 都能到达 D. 都不能到达 2. 运行以下程序(小象仅有两个造型),小象的造型是…

最简单的SpringBoot+MyBatis多数据源实现

最简单的SpringBootMyBatis多数据源实现1.数据库准备2.环境准备3.代码部分3.1多数据源配置2.测试随着应用用户数量的增加,相应的并发请求的数量也会跟着不断增加,慢慢地,单个数据库已经没有办法满足频繁的数据库操作请求了,在某些…

【JeecgBoot-Vue3】第4节 目录结构与常用组件介绍

一、项目的目录结构讲解 1. src/api/ 存放API相关信息 src/api/存放的是调用后台api接口相关信息src/api/commonapi.tsapi接口信息2. src/assets 静态资源 src/assets静态资源 src/assets/icons 图标 src/assets/images 图片 src/assets/less 样式src/assets/svgsvg图像3. s…

函数编程:强大的 Stream API

函数编程:强大的 Stream API 每博一文案 只要有人的地方,世界就不会是冰冷的,我们可以平凡,但绝对不可以平庸。—————— 《平凡的世界》人活着,就得随时准备经受磨难。他已经看过一些书,知道不论是普通…

Python API教程:API入门

什么是API? 一个API,或被称为应用程序接口,是一个服务器为你提供一个接收或发送数据的代码。API通常用来接收数据。 本文就集中焦点在此话题中。 当我们想从一个API中接收数据,我们需要开始请求。请求可以包含整个Web。例如&am…

Vue基础18之github案例、vue-resource

Vue基础18github案例静态页面第三方样式引入(以bootstrap举例)App.vueSearch.vueList.vue列表展示接口地址使用全局事件总线进行兄弟间组件通信Search.vueList.vue完善案例List.vueSearch.vue补充知识点:{...this.info,...this.dataObj}效果呈…

Serverless

Serverless:云计算的下一个十年 最近几年的技术圈,对于 Serverless 技术的讨论异常火热,在业内也有了很多成熟的案例,国外发展较早,比较有代表性的就是亚马逊和谷歌, 而在国内,腾讯和阿里两位巨…

Maven使用教程

1.什么是Maven? 当我们在创建一个使用Spring的Web项目就需要引入大量的jar包。一个项目Jar包的数量极多,并且Jar包之间的关系错综复杂,一个Jar包往往又会引用其他Jar包,缺少任何一个Jar包都会导致项目编译失败。 以往开发项目时…

GraphPad Prism v9.5.1.733 科研绘图软件多语言

GraphPad Prism集生物统计、曲线拟合和科技绘图于一体,其所具有的功能均非常实用和精炼,包括了一些特色的功能,如ROC曲线分析、Bland-Altman分析等;曲线拟合功能是GraphPad Prism8 汉化版超越其他统计软体的制胜法宝,GraphPad Prism8 汉化版的线性/非线性拟合功能使用操作…

JVM运行时数据区—Java虚拟机栈

虚拟机栈的背景 由于跨平台性的设计,java的指令都是根据栈来设计的。不同平台CPU架构不同,所以不能设计为基于寄存器的。 根据栈设计的优点是跨平台,指令集小,编译器容易实现,缺点是性能下降,实现同样的功…

python制作【法律条文查询工具】妈妈再也不担心我法盲了

前言 嗨喽~大家好呀,这里是魔王呐 ❤ ~! 更多教程源码资料电子书: 点击此处跳转文末名片获取 环境准备8 Python 3.8 Pycharm 《中华人民共和国刑法》 效果展示 打算做个简单的界面,主要功能就是查询法律条文 代码展示 查询器界面 设定界面大小 …

戴眼镜检测和识别2:Pytorch实现戴眼镜检测和识别(含戴眼镜数据集和训练代码)

Pytorch实现戴眼镜检测和识别(含戴眼镜数据集和训练代码) 目录 Pytorch实现戴眼镜检测和识别(含戴眼镜数据集和训练代码) 1.戴眼镜检测和识别方法 2.戴眼镜数据集 3.人脸检测模型 4.戴眼镜分类模型训练 (1)项目安装 (2)准…

反向代理和负载均衡有何区别?

反向代理和负载均衡是两种常用的网络架构模式,它们可以一起使用来提高网站的性能和可靠性,很多人会把这两者混淆,实际上,这两者的作用略有不同,今天我们就来详细说说具体区别是什么。一、反向代理(Reverse …