【Python--网络编程之TCP三次握手】

🚀 作者 :“码上有前”
🚀 文章简介 :Python开发技术
🚀 欢迎小伙伴们 点赞👍、收藏⭐、留言💬
在这里插入图片描述

Python网络编程之[TCP三次握手]

  • 往期内容
  • 代码见资源,效果图如下
  • 一、实验要求
  • 二、协议原理
    • 2.1 TCP协议
    • 2.2 TCP三次握手
    • 2.3 TCP四次挥手
  • 三、程序功能与流程
  • 四、分析程序代码
    • 4.1 构建TCPServer
    • 4.2 构建TCPClient
    • 4.3 GUI可视化
  • 五、总结
  • 六、参考文献

往期内容

【Python–vscode常用快捷键,必收藏!】
【Python–代码规范 】
【Python --优雅代码写法】
【Python–Python2.x与Python3.x的区别】
【Python–Web应用框架大比较】
【Python—内置函数】
【Python—六大数据结构】
【python–迭代生成器闭包面向对象继承多态】
【Python–定时任务的四种方法】
【Python–迭代器和生成器的区别】
【Python–读写模式全解】
【Python–高级教程】
【Python–网络编程之DHCP服务器】
【Python–网络编程之Ping命令的实现】
【Python–网络编程之TCP三次握手】

代码见资源,效果图如下

一、实验要求

  1. 基本要求:理解三次握手、四次挥手过程及序号变化。
  2. 设计语言:Python、C/C++。
  3. 原理:利用 TCP 报文中的 SYN、SYN+ACK、ACK 报文与服务器某程序(例如端口 80、端口 23)建立 TCP 连接,然后向服务器发送部分数据,最后用四报文挥手释放连接。亦可参考计算机网络综合实验教程中的实验 11,编写一个简单的服务器程序,并与其建立连接、传输数据并释放连接。
  4. 技术难点:TCP 握手和挥手过程中 seq 和 ack 的变化情况,准确构建对应的 TCP 报文段,发送这些报文段,接收并分析返回结果。另外,当运行程序的计算机收到服务器发来的 TCP 报文段之后(例如第二次握手的报文),计算机可会发送 RST 报文给服务器,这个 RST 报文必须丢弃,如何丢弃 RST 报文,需要在 linux 中实现(windows 丢弃 RST 包的方法较难),因此,该程序需在 Linux 中实现并运行。

二、协议原理

2.1 TCP协议

TCP(Transmission Control Protocol)是一种面向连接的、可靠的传输层协议,用于在计算机网络中传输数据。它是互联网协议套件(TCP/IP)中最常用的协议之一,被广泛用于应用层协议(如HTTP、FTP、SMTP等)的可靠数据传输。
下面是对TCP协议及其特点的详细解释:

  1. 面向连接:在进行数据传输之前,发送方和接收方需要通过三次握手建立一个连接。连接的建立包括发送方向接收方发送一个连接请求(SYN),接收方向发送方发送一个连接确认(SYN-ACK),以及发送方向接收方发送一个连接确认(ACK)。连接的建立确保了双方都愿意进行数据传输,并为后续的数据传输提供了必要的准备。
  2. 可靠性:TCP通过使用序列号、确认应答和重传等机制来确保可靠的数据传输。每个TCP报文段都包含一个序列号,接收方通过确认应答来告知发送方已经接收到哪些数据。如果发送方没有接收到确认应答或者接收到了超时的确认应答,它将会重新发送未确认的数据。这种机制确保了数据的可靠性,即使在网络丢包或出现错误的情况下也能够进行恢复。
  3. 流量控制:TCP使用滑动窗口机制来进行流量控制。接收方通过告知发送方自己的缓冲区大小来限制发送方发送的数据量。发送方根据接收方提供的窗口大小来控制发送的数据量,以确保接收方能够及时处理接收到的数据。
  4. 拥塞控制:TCP使用拥塞控制算法来避免网络拥塞。发送方通过动态调整发送的数据量来适应网络的状况。当网络拥塞时,发送方减少发送的数据量,以降低网络负载。当网络状况改善时,发送方逐渐增加发送的数据量,以提高数据传输的效率。
  5. 有序性:TCP保证数据的有序传输。接收方根据接收到的TCP报文段的序列号对它们进行重新排序,以确保数据按照发送方发送时的顺序进行传输。
  6. 双工通信:TCP支持全双工通信,即发送方和接收方可以同时进行数据的发送和接收。这使得双方能够同时进行数据交换,提高了通信的效率。
    总结起来,TCP是一种可靠的面向连接的传输协议,通过建立连接、使用序列号和确认应答、流量控制和拥塞控制等机制,提供了可靠的数据传输、有序性、流量控制和拥塞控制等功能。它是互联网上应用层协议进行可靠数据传输的基础。
    上述讲到了TCP协议及其特点,此外,TCP协议在互联网中有广泛的应用场景,以下是一些常见的应用场景:
  7. 网页浏览:TCP作为HTTP协议的可靠传输层协议,用于在浏览器和服务器之间传输网页内容。当您在浏览器中输入网址并请求网页时,TCP协议负责将网页内容分成多个TCP报文段,并通过互联网将它们从服务器传输到您的浏览器。
  8. 文件传输:TCP协议也被用于文件传输协议,如FTP(File Transfer Protocol)。通过TCP的可靠性和流量控制,FTP可以确保文件在客户端和服务器之间的可靠传输。
  9. 电子邮件:TCP协议用于电子邮件的传输。当您发送电子邮件时,您的电子邮件客户端使用TCP将邮件传输到邮件服务器,而接收方的电子邮件客户端使用TCP从邮件服务器接收邮件。
  10. 远程登录:TCP协议被用于远程登录协议,如Telnet和SSH。这些协议允许用户通过网络远程登录到远程计算机,并与其进行交互。TCP协议提供了可靠的数据传输和双向通信的支持,确保用户与远程计算机之间的交互是稳定和可靠的。
  11. 数据库访问:TCP协议常被用于数据库访问,如MySQL和PostgreSQL。通过TCP协议,客户端可以与数据库服务器建立连接,并进行查询、更新和管理数据库中的数据。
  12. 实时通信:TCP协议也被用于实时通信应用,如即时通讯(Instant Messaging)和语音通话。通过TCP的可靠性和流量控制,这些应用可以确保消息和音频数据在用户之间的实时传输。
    需要注意的是,尽管TCP协议在许多应用中被广泛使用,但对于某些特定的应用,如实时视频流或大规模数据传输等,可能会选择使用UDP协议,因为UDP具有更低的延迟和更高的传输速度,但可靠性较差。因此,在选择使用TCP还是UDP时,需要根据应用的需求来做出权衡。
    上述了解了TCP协议、特点还有它适合的场景,为了更加详细的了解他,需要掌握它的报文格式:
    TCP(Transmission Control Protocol)报文格式如下所示:
    在这里插入图片描述

下面是对各个字段的详细解释:

  1. 源端口号(Source Port):16位字段,用于标识发送方的应用程序或服务的端口号。

  2. 目标端口号(Destination Port):16位字段,用于标识接收方的应用程序或服务的端口号。

  3. 序列号(Sequence Number):32位字段,用于对TCP数据流中的每个字节进行编号。序列号用来保证数据的顺序性。

  4. 确认号(Acknowledgment Number):32位字段,用于确认已经收到的数据的序列号。确认号表示期望接收的下一个字节的序列号。

  5. 数据偏移(Data Offset):4位字段,表示TCP报文头部的长度,以4字节为单位。TCP报文头长度最小为20字节。

  6. 保留(Reserved):6位字段,保留用于将来的扩展。

  7. URG标志(URG):1位字段,表示紧急指针字段是否有效。

  8. ACK标志(ACK):1位字段,表示确认号字段是否有效。

  9. PSH标志(PSH):1位字段,表示接收方是否应该尽快将数据交给应用层。

  10. RST标志(RST):1位字段,表示中断连接。

  11. SYN标志(SYN):1位字段,用于建立连接时进行同步。

  12. FIN标志(FIN):1位字段,表示发送方已经完成数据的发送,准备关闭连接。

  13. 窗口大小(Window Size):16位字段,表示接收方可接收的字节数。

  14. 校验和(Checksum):16位字段,用于检验TCP报文的完整性。

  15. 紧急指针(Urgent Pointer):16位字段,用于指示紧急数据的字节偏移量。

  16. 选项(Options):可选字段,用于在TCP报文中添加一些可选的功能或参数。

  17. 数据(Data):可选字段,用于携带应用层的数据。
    TCP报文格式中的各个字段共同构成了TCP协议数据传输的头部部分,提供了必要的控制和管理信息,以实现可靠的、有序的数据传输。

2.2 TCP三次握手

建立一个连接需要三次握手,而终止一个连接要经过四次挥手(也有将四次挥手叫做四次握手的)。这由TCP的半关闭(half-close)造成的。所谓的半关闭,其实就是TCP提供了连接的一端在结束它的发送后还能接收来自另一端数据的能力。
TCP 连接的拆除需要发送四个包,因此称为四次挥手(Four-way handshake),客户端或服务端均可主动发起挥手动作。
刚开始双方都处于ESTABLISHED 状态,假如是客户端先发起关闭请求。四次挥手的过程如下:
• 第一次挥手:客户端发送一个 FIN 报文,报文中会指定一个序列号。此时客户端处于 FIN_WAIT1 状态。
即发出连接释放报文段(FIN=1,序号seq=u),并停止再发送数据,主动关闭TCP连接,进入FIN_WAIT1(终止等待1)状态,等待服务端的确认。
• 第二次挥手:服务端收到 FIN 之后,会发送 ACK 报文,且把客户端的序列号值 +1 作为 ACK 报文的序列号值,表明已经收到客户端的报文了,此时服务端处于 CLOSE_WAIT 状态。
即服务端收到连接释放报文段后即发出确认报文段(ACK=1,确认号ack=u+1,序号seq=v),服务端进入CLOSE_WAIT(关闭等待)状态,此时的TCP处于半关闭状态,客户端到服务端的连接释放。客户端收到服务端的确认后,进入FIN_WAIT2(终止等待2)状态,等待服务端发出的连接释放报文段。
• 第三次挥手:如果服务端也想断开连接了,和客户端的第一次挥手一样,发给 FIN 报文,且指定一个序列号。此时服务端处于 LAST_ACK 的状态。
即服务端没有要向客户端发出的数据,服务端发出连接释放报文段(FIN=1,ACK=1,序号seq=w,确认号ack=u+1),服务端进入LAST_ACK(最后确认)状态,等待客户端的确认。
• 第四次挥手:客户端收到 FIN 之后,一样发送一个 ACK 报文作为应答,且把服务端的序列号值 +1 作为自己 ACK 报文的序列号值,此时客户端处于 TIME_WAIT 状态。需要过一阵子以确保服务端收到自己的 ACK 报文之后才会进入 CLOSED 状态,服务端收到 ACK 报文之后,就处于关闭连接了,处于 CLOSED 状态。
即客户端收到服务端的连接释放报文段后,对此发出确认报文段(ACK=1,seq=u+1,ack=w+1),客户端进入TIME_WAIT(时间等待)状态。此时TCP未释放掉,需要经过时间等待计时器设置的时间2MSL后,客户端才进入CLOSED状态。
收到一个FIN只意味着在这一方向上没有数据流动。客户端执行主动关闭并进入TIME_WAIT是正常的,服务端通常执行被动关闭,不会进入TIME_WAIT状态。
在socket编程中,任何一方执行close()操作即可产生挥手操作。
一旦服务器收到客户端的ACK报文,TCP连接就正式建立起来了。此时,客户端和服务器之间可以开始进行数据传输。
三次握手的目的是确保客户端和服务器都能够发送和接收数据,并且双方已经同意了初始的序列号。通过这个过程,TCP可以建立一个可靠的双向通信通道,以确保数据传输的可靠性和完整性。
需要注意的是,三次握手过程中可能会出现延迟或丢失的情况。如果某个步骤的报文丢失或延迟到达,TCP会根据超时和重传机制进行处理,以确保握手过程的完成。
在这里插入图片描述

2.3 TCP四次挥手

挥手为什么需要四次?因为当服务端收到客户端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当服务端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉客户端,“你发的FIN报文我收到了”。只有等到我服务端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四次挥手。
TCP(Transmission Control Protocol)使用四次挥手(four-way handshake)来关闭一个已建立的连接。四次挥手确保了通信双方在终止连接时的正常关闭,以避免数据丢失或不完整。
下面是TCP四次挥手的详细过程:

  1. 第一步(FIN):当客户端决定关闭连接时,它发送一个FIN(Finish)报文给服务器。这个报文表示客户端不再发送数据,但仍然可以接收服务器发送的数据。
  2. 第二步(ACK):服务器收到客户端的FIN报文后,发送一个ACK(Acknowledgment)报文作为确认。这个报文表示服务器已经收到了客户端的关闭请求。
  3. 第三步(FIN):当服务器也准备关闭连接时,它发送一个FIN报文给客户端。这个报文表示服务器不再发送数据。
  4. 第四步(ACK):客户端收到服务器的FIN报文后,发送一个ACK报文作为确认。这个报文表示客户端已经收到了服务器的关闭请求。
    一旦双方都发送了FIN和ACK报文,并收到了对方的确认,TCP连接就会正式关闭。此时,双方都不再发送或接收数据。
    四次挥手的目的是确保双方都能够完成数据的传输和接收,并在关闭连接时进行协调。通过这个过程,TCP可以正常地关闭连接,释放相关的资源,并确保数据的完整性。
    需要注意的是,在四次挥手过程中可能会出现延迟、丢失或重复的报文。TCP通过超时和重传机制来处理这些情况,以确保挥手过程的顺利完成。
    在这里插入图片描述

TCP状态变迁图

三、程序功能与流程

我们首先创建了一个客户端套接字,然后使用 connect() 方法与服务器建立 TCP 连接,并发送 SYN 报文。
接着,我们接收服务器返回的 SYN+ACK 报文,并发送 ACK 报文,完成三次握手,建立了连接。
然后,我们向服务器发送数据,并使用 recv() 方法接收服务器的响应数据。
接着,我们发送四报文挥手释放连接:发送 FIN 报文,接收 FIN+ACK 报文,发送 ACK 报文,完成四次挥手,释放连接。
最后,我们使用tkinter中进行图形化界面GUI,并展示出来。

四、分析程序代码

4.1 构建TCPServer

在这里插入图片描述

上述代码是一个简单的 TCP 服务器类 TCPServer 的示例。
解释代码如下:

  1. def __init__(self, port):: 定义了 TCPServer 类的构造函数。在创建 TCPServer 类的实例时,需要传入服务器的端口号 port
  2. self.port = port: 将传入的端口号保存到类的属性 port 中。
  3. self.server_socket = None: 定义了一个名为 server_socket 的属性,初始值为 None。这个属性用于存储服务器的套接字对象。
  4. self.server_thread = None: 定义了一个名为 server_thread 的属性,初始值为 None。这个属性用于存储用于监听客户端连接的线程对象。
  5. def start(self):: 定义了一个 start 方法,用于启动服务器。
  6. start 方法中:
    • self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM): 创建一个服务器套接字对象 server_socket,用于监听客户端连接。
    • self.server_socket.bind(('192.168.1.5', self.port)): 将服务器套接字绑定到指定的 IP 地址和端口号。在这个示例中,IP 地址为 '192.168.1.5',端口号为构造函数中传入的 port
    • self.server_socket.listen(1): 开始监听客户端连接请求,参数 1 表示最多允许同时连接的客户端数量为 1。
    • print("服务器已启动,等待客户端连接..."): 打印消息表示服务器已启动,等待客户端连接。
  7. self.server_thread = threading.Thread(target=self._listen): 创建一个线程对象 server_thread,该线程将调用 _listen 方法来监听客户端连接。_listen 方法是一个内部方法,用于实际处理客户端连接。
  8. self.server_thread.start(): 启动线程,开始监听客户端连接。
  9. def stop(self):: 定义了一个 stop 方法,用于停止服务器。
  10. stop 方法中:
    • if self.server_socket:: 检查服务器套接字对象是否存在。
    • self.server_socket.close(): 关闭服务器套接字。
    • if self.server_thread:: 检查监听线程对象是否存在。
    • self.server_thread.join(): 等待监听线程结束。
      总体而言,这段代码实现了一个简单的 TCP 服务器类 TCPServer,通过调用 start 方法可以启动服务器并开始监听客户端连接,通过调用 stop 方法可以停止服务器并关闭套接字。
      在这里插入图片描述

上述代码定义了一个名为 _listen 的方法,用于在服务器上监听客户端连接,并处理 TCP 三次握手的过程。
解释代码如下:

  1. def _listen(self):: 定义了一个名为 _listen 的方法,用于监听客户端连接并处理三次握手过程。

  2. while True:: 进入一个无限循环,持续监听客户端连接。

  3. client_socket, client_address = self.server_socket.accept(): 通过调用服务器套接字的 accept() 方法,接受客户端的连接请求,返回一个新的套接字对象 client_socket 和客户端的地址信息 client_address

  4. print(f"客户端 {client_address} 连接成功!"): 打印消息表示客户端连接成功。

  5. syn_packet = client_socket.recv(1024): 从客户端套接字接收客户端发送的 SYN 包,最多接收 1024 字节的数据。

  6. print("客户端发送的 SYN 包==", syn_packet): 打印客户端发送的 SYN 包的字节流。

  7. seq_num = int.from_bytes(syn_packet, byteorder='big'): 将接收到的 SYN 包字节流转换为整数,获取序列号 seq_num

  8. ack_num = seq_num + 1: 计算 SYN+ACK 包的确认号,即客户端发送的 SYN 包序列号加 1。

  9. ack_bytes = ack_num.to_bytes(4, byteorder='big'): 将确认号 ack_num 转换为 4 字节的大端字节序。

  10. syn_value = 12345: 设置 SYN 包的序列号 syn_value

  11. syn_bytes = syn_value.to_bytes(4, byteorder='big'): 将 SYN 包的序列号 syn_value 转换为 4 字节的大端字节序。

  12. ack_syn_bytes = ack_bytes + syn_bytes: 将 ACK 字节流和 SYN 字节流拼接在一起,形成 SYN+ACK 包的字节流。

  13. client_socket.send(ack_syn_bytes): 将 SYN+ACK 包的字节流发送给客户端。

  14. ack_packet = client_socket.recv(1024): 从客户端套接字接收客户端发送的 ACK 包,最多接收 1024 字节的数据。

  15. print("获取客户端发送的 ACK 包==", ack_packet): 打印客户端发送的 ACK 包的字节流。

  16. client_socket.close(): 关闭客户端套接字。

  17. print(f"客户端 {client_address} 连接已关闭\n"): 打印消息表示客户端连接已关闭。

  18. self._show_popup(syn_packet, ack_syn_bytes, ack_packet): 调用 _show_popup 方法,显示弹出框,展示 TCP 三次握手过程中的包信息。

  19. client_socket.close(): 再次关闭客户端套接字。

  20. print(f"客户端 {client_address} 连接已关闭\n"): 打印消息表示客户端连接已关闭。
    总体而言,这段代码在一个循环中监听客户端连接,接收客户端发送的 SYN 包,发送 SYN+ACK 包,接收客户端发送的 ACK 包,并显示弹出框展示三次握手过程中的包信息。连接关闭后,循环继续监听下一个客户端连接。
    在这里插入图片描述

上述代码定义了一个名为 _show_popup 的方法,用于显示一个弹出框,展示 TCP 三次握手过程中发送的 SYN 包、SYN+ACK 包和 ACK 包的信息。
解释代码如下:

  1. def _show_popup(self, syn_packet_info, syn_ack_packet, ack_packet_info):: 定义了一个名为 _show_popup 的方法,它有三个参数:syn_packet_infosyn_ack_packetack_packet_info,分别表示 SYN 包、SYN+ACK 包和 ACK 包的信息。
  2. popup_title = "TCP 三次握手": 定义了弹出框的标题为 “TCP 三次握手”。
  3. popup_message = f"客户端发送的 SYN 包:\n{syn_packet_info}\n{int.from_bytes(syn_packet_info, byteorder='big')}\n" \: 构建了弹出框的消息内容。使用了 f-string 格式化字符串,包括客户端发送的 SYN 包信息和对应的整数值。
  4. f"服务器发送的 SYN+ACK 包:\n{syn_ack_packet}\n{int.from_bytes(syn_ack_packet, byteorder='big')}\n": 在消息内容中添加了服务器发送的 SYN+ACK 包的信息和整数值。
  5. f"客户端发送的 ACK 包:\n{ack_packet_info}\n{int.from_bytes(syn_ack_packet, byteorder='big')}\n": 在消息内容中添加了客户端发送的 ACK 包的信息和整数值。
  6. messagebox.showinfo(popup_title, popup_message): 调用 messagebox.showinfo() 方法显示一个信息弹出框。popup_title 是弹出框的标题,popup_message 是弹出框的消息内容。
    总体而言,这段代码定义了一个方法 _show_popup,用于在图形化界面中显示一个弹出框,展示 TCP 三次握手过程中发送的 SYN 包、SYN+ACK 包和 ACK 包的信息。弹出框显示的内容包括包的原始信息以及将其解析为整数值后的结果。

4.2 构建TCPClient

在这里插入图片描述

上述代码是一个连接服务器的函数 connect(self) 的示例。
解释代码如下:

  1. client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM): 创建一个客户端套接字对象 client_socket,用于与服务器建立 TCP 连接。

  2. client_socket.connect((self.server_ip, self.server_port)): 使用 connect() 方法连接到指定的服务器 IP 地址和端口号。self.server_ipself.server_port 是类属性,表示服务器的 IP 地址和端口号。

  3. print("与服务器连接成功!"): 打印消息表示与服务器成功建立连接。

  4. 构建 SYN 报文并发送给服务器:

    • client_seq = 54321: 客户端的初始序列号。
    • syn_packet = client_seq.to_bytes(4, byteorder='big'): 将客户端的序列号转换为 4 字节的大端字节序,构建 SYN 报文。
    • client_socket.sendall(syn_packet): 将 SYN 报文发送给服务器。
  5. print("发送给服务器的 SYN 报文syn_packet==", syn_packet): 打印发送给服务器的 SYN 报文的内容。

  6. 接收服务器发送的 SYN+ACK 报文:

    • syn_ack_packet = client_socket.recv(1024): 使用 recv() 方法接收服务器发送的 SYN+ACK 报文。1024 是指定的接收缓冲区大小。
  7. print("接收到服务器发送的 SYN+ACK 报文, syn_ack_packet==", syn_ack_packet, syn_ack_packet.hex()): 打印接收到的 SYN+ACK 报文的内容。

  8. 解析服务器发送的 SYN+ACK 报文:

    • server_ack = int.from_bytes(syn_ack_packet[:4], byteorder='big'): 提取接收到的 SYN+ACK 报文中的确认号。
    • server_seq = int.from_bytes(syn_ack_packet[4:], byteorder='big'): 提取接收到的 SYN+ACK 报文中的序列号。
  9. print("server_seq, server_ack===", server_seq, server_ack): 打印服务器的序列号和确认号。

  10. 检查服务器发送的 SYN+ACK 报文的确认号,并构建 ACK 报文发送给服务器:

    • client_ack = server_seq + 1: 根据服务器的序列号计算客户端的确认号。
    • ack_packet = client_ack.to_bytes(4, byteorder='big'): 将客户端的确认号转换为 4 字节的大端字节序,构建 ACK 报文。
    • client_socket.sendall(ack_packet): 将 ACK 报文发送给服务器。
  11. print("TCP 握手完成,连接建立成功!"): 打印消息表示 TCP 握手过程完成,连接成功建立。
    总体而言,这段代码通过客户端套接字与服务器建立 TCP 连接,进行了三次握手的过程,并打印了握手过程中发送和接收的报文内容。最后,根据服务器发送的 SYN+ACK 报文,构建并发送了客户端的 ACK 报文,完成了连接的建立。

4.3 GUI可视化

在这里插入图片描述
上述代码用于创建一个基于 tkinter 库的 GUI 应用程序。
解释代码如下:

  1. root = tk.Tk(): 创建一个名为 root 的根窗口对象,并将其赋值给变量 root。这个根窗口是 GUI 应用程序的最顶层窗口。
  2. root.title("TCP连接测试工具"): 设置根窗口的标题为 “TCP连接测试工具”。
  3. root.geometry("350x350"): 设置根窗口的大小为宽度 350 像素、高度 350 像素。
  4. app = App(root): 创建一个 App 类的实例,并传入根窗口对象 root。这样就将 App 类的 GUI 元素添加到了根窗口中。
  5. root.mainloop(): 进入主事件循环,该函数会一直运行,直到用户关闭窗口。在事件循环中,程序会等待用户的交互事件(如按钮点击、键盘输入等),并调用相应的事件处理函数来响应用户操作。
    总体而言,这段代码创建了一个 GUI 应用程序的根窗口,并在根窗口中添加了 App 类的 GUI 元素。然后,通过调用 root.mainloop() 进入主事件循环,使程序保持运行状态,等待用户的交互操作。

在这里插入图片描述

上述代码是一个使用 tkinter 库创建图形用户界面(GUI)的 Python 类 App 的示例。
解释代码如下:

  1. class App:: 定义了一个名为 App 的类,用于创建 GUI 应用程序。
  2. def __init__(self, root):: __init__ 方法是类的构造函数,在创建 App 类的实例时被调用。self 表示类的实例本身,root 是传入的根窗口对象。
  3. self.root = root: 将传入的根窗口对象保存到类的属性 root 中。
  4. self.server = '192.168.1.5': 定义了一个名为 server 的字符串属性,表示服务器的 IP 地址。
  5. self.client = None: 定义了一个名为 client 的属性,初始值为 None
  6. 接下来是一系列 GUI 元素的创建和配置,包括标签 (tk.Label)、文本输入框 (tk.Entry) 和按钮 (tk.Button)。
    • self.server_port_label, self.server_port_entry: 用于输入服务器的端口号。
    • self.server_start_button, self.server_stop_button: 分别用于启动和停止服务器。
    • self.client_ip_label, self.client_ip_entry: 用于输入服务器的 IP 地址。
    • self.client_port_label, self.client_port_entry: 用于输入服务器的端口号。
    • self.client_connect_button: 用于连接服务器。
  7. command=self.start_server, command=self.stop_server, command=self.connect_server: 这些是按钮的 command 参数,表示按钮被点击时要执行的函数。
  8. self.start_server, self.stop_server, self.connect_server: 这些是 App 类中定义的方法,用于处理按钮点击事件的逻辑。
    总体而言,这段代码创建了一个基本的 GUI 应用程序,包含了服务器的启动和停止按钮以及客户端的连接按钮。它为用户提供了输入服务器 IP 地址和端口号的文本框,并通过调用相应的方法处理按钮点击事件。

五、总结

上述实验涉及了使用 TCP 协议建立连接、传输数据和释放连接的过程。简要流程如下:

  1. 创建客户端套接字,并使用 connect() 方法与服务器建立 TCP 连接,发送 SYN 报文。
  2. 接收服务器返回的 SYN+ACK 报文,并发送 ACK 报文,完成三次握手,建立连接。
  3. 向服务器发送数据,并使用 recv() 方法接收服务器的响应数据。
  4. 发送四报文挥手释放连接:发送 FIN 报文,接收 FIN+ACK 报文,发送 ACK 报文,完成四次挥手,释放连接。
  5. 关闭客户端套接字。

六、参考文献

  1. “TCP Congestion Control” by Van Jacobson (1988): 这篇论文介绍了 TCP 拥塞控制算法的基本原理,其中包括慢启动、拥塞避免和快速重传/恢复等机制。
  2. “TCP/IP Illustrated, Volume 1: The Protocols” by W. Richard Stevens (1994): 这本书并非论文,但它详细介绍了 TCP/IP 协议栈的工作原理和实现细节,对理解 TCP 协议非常有帮助。
  3. “TCP/IP Performance Analysis for Space Communications” by Sally Floyd and Van Jacobson (1995): 这篇论文深入分析了 TCP 的性能问题,特别是在高延迟和高丢包率的网络环境下的表现,并提出了一些改进的建议。
  4. “TCP Vegas: New Techniques for Congestion Detection and Avoidance” by Lawrence S. Brakmo and Larry L. Peterson (1995): 该论文介绍了 TCP Vegas 拥塞控制算法,它通过测量网络往返时间的变化来检测拥塞,并采取相应的措施避免拥塞。
  5. “TCP/IP Performance: A Hierarchy of Models” by Jitendra Padhye, Victor Firoiu, and Don Towsley (2000): 这篇论文提出了一个层次化的模型,用于理解和分析 TCP 的性能问题,包括带宽利用率、时延、丢包和吞吐量等方面。
    都看到这了,点个赞吧🚀

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

YOLOv8制作自定义数据集并训练

YOLOv8制作自定义数据集并训练 前言一、制作自定义数据集1、建立相应文件夹2、下载图片3、为图片打标签(1)安装labelimg(2)打开labelimg(3)标记图片 二、按比例移动自定义数据集中的内容三、建立数据集测试…

「算法」二分查找1:理论细节

🎇个人主页:Ice_Sugar_7 🎇所属专栏:算法详解 🎇欢迎点赞收藏加关注哦! 二分查找算法简介 这个算法的特点就是:细节多,出错率高,很容易就写成死循环有模板,但…

MySQL篇之SQL优化

一、表的设计优化 表的设计优化(参考阿里开发手册《嵩山版》): 1. 比如设置合适的数值(tinyint int bigint),要根据实际情况选择。 2. 比如设置合适的字符串类型(char和varchar&#xff09…

UnityShader——06UnityShader介绍

UnityShader介绍 UnityShader的基础ShaderLab UnityShader属性块介绍 Properties {//和public变量一样会显示在Unity的inspector面板上//_MainTex为变量名,在属性里的变量一般会加下划线,来区分参数变量和临时变量//Texture为变量命名//2D为类型&…

OpenAI Sora 初体验

OpenAI Sora 初体验 就在刚刚,OpenAI 再次投下一枚重磅炸弹——Sora,一个文本到视频生成模型。 我第一时间体验了 Sora。看过 Sora 的能力后,我真的印象深刻。对细节的关注、无缝的角色刻画以及生成视频的绝对质量真正将可能性提升到了一个新…

程序员搞什么副业才有性价比?

干一行恨一行,三百六十行,行行干破防! 一份稳定的主业固然重要,但是有性价比的副业更令人心动。朝九晚五的工作日复一日,当然也可能是996的生活反复捶打。从整体来讲,程序员算是高收入群体,但往…

GitLab配置SSHKey

段落一:什么是SSH密钥 SSH(Secure Shell)是一种网络协议,用于安全地远程登录和执行命令。SSH密钥是一种用于身份验证的加密文件,它允许您在与远程服务器通信时,无需输入密码即可进行认证。在GitLab中配置S…

小苯的数组切分 ---- 牛客月赛

题目描述 qionghuaqionghuaqionghua 给了小苯一个长度为 n 的数组 a&#xff0c;希望小苯将数组 aaa 分为恰好非空的三段。即&#xff1a;[1,l−1],[l,r],[r1,n]这三段&#xff0c;其中 1< l≤r<n。接着&#xff1a; ∙ 第一段的所有数字做 ⊕&#xff08;按位异或&…

实现低功耗设计的嵌入式系统技术

&#xff08;本文为简单介绍&#xff0c;观点来源网络&#xff09; 在嵌入式系统设计中&#xff0c;追求低功耗已成为一个核心指标&#xff0c;旨在延长设备的运行时间并提升能效。实现这一目标的途径是多元的&#xff0c;涉及从硬件选型到软件算法的各个层面。 首先&#xf…

从六大晶圆厂财报看半导体行业2024年复苏

2023年&#xff0c;全球半导体行业经历了重大调整&#xff0c;在面临高通胀风险及库存水平调整的过程中&#xff0c;市场短期展望并不明朗。然而&#xff0c;根据TrendForce对全球六大顶尖半导体代工厂&#xff08;TSMC、三星电子、英特尔、GlobalFoundries、UMC和SMIC&#xf…

循环、数组、match

for循环 循环&#xff1a;周而复始 For&#xff08;临时变量&#xff1b;循环条件&#xff1b;腰间变更&#xff09;{ 循环体 } For循环可以嵌套 while循环 声明变量 While&#xff08;条件&#xff09;{ 循环体 变量的变化} do while循环 do{ 执行语句&#xff1b; …

el-upload组件的简单使用

最近公司的一个二期项目&#xff0c;开始要求复刻原有一期的功能页面。原先一期又不打算继续维护了&#xff0c;源码都没有。页面基本都涉及到了文件上传&#xff0c;以前很少使用到这个组件&#xff0c;公司有现成的表单设计器&#xff0c;文件上传都在组件里面拖动上传。在这…

智慧城管建设方案

第5章智慧城管可视化平台 5.1 视频综合管理平台 5.1.1 平台架构 整个视频监控管理平台在架构上分为五个层次&#xff0c;底层是基础硬件支撑层和基础软件支撑层&#xff0c;是支持整个系统运行必要的系统硬件和环境&#xff0c;网络基础设施包括了电子政务网、视频监控专网、…

WS2812B彩灯 STM32库函数开发:PWM+DMA(stm32f407VET6)

这里写目录标题 1、概述2、芯片级联方法3、数据传输特性4、程序实例4.1、硬件电路4.2、定时器初始化4.3、DMA初始化4.4、RGB数据驱动 5、完整代码5.1、WS2812B.c5.2、WS2812B.h5.3、main.c 1、概述 WS2812B是一种常见的RGB LED灯带&#xff0c;每个灯珠内部都有一个芯片控制&a…

MATLAB进行特征选择

特征选择是机器学习和统计建模中的重要步骤,它涉及选择最相关、最有信息价值的特征,以提高模型性能、降低过拟合风险,并加速训练过程。以下是一些常见的特征选择方法: (1)方差选择法 计算各个特征的方差,然后根据阈值,选择方差大于阈值的特征作为筛选出来的特…

恒流模块与常用电容

户外电源电芯&#xff1a;DJ采用无热中心设计&#xff1a;每个电芯都有一部分裸露在外面&#xff0c;保证良好散热上 固态电容相较于普通电解电容具有更高的电气性能、更长的使用寿命和更稳定的温度特性&#xff0c;但成本也相对较高。固态电容在1块左右&#xff0c;电解电容在…

点亮代码之灯,程序员的夜与电脑

在科技的海洋里&#xff0c;程序员是那些驾驶着代码船只&#xff0c;穿梭于虚拟世界的探险家。他们手中的键盘是航行的舵&#xff0c;而那台始终不愿关闭的电脑&#xff0c;便是他们眼中永不熄灭的灯塔。有人说&#xff0c;程序员不喜欢关电脑&#xff0c;这究竟是为什么呢&…

vue3之setup的基本使用

setup是一个全新的配置项&#xff0c;值是一个函数&#xff0c;既然是配置项&#xff0c;是否与data、methods是兄弟&#xff1f; 没错&#xff0c;确实是兄弟关系&#xff0c;只不过到了vue3&#xff0c;就不怎么使用data这些配置项&#xff0c;会使用setup&#xff0c;让我为…

牛客网SQL进阶128:未完成试卷数大于1的有效用户

官网链接&#xff1a; 未完成试卷数大于1的有效用户_牛客题霸_牛客网现有试卷作答记录表exam_record&#xff08;uid用户ID, exam_id试卷ID, st。题目来自【牛客题霸】https://www.nowcoder.com/practice/46cb7a33f7204f3ba7f6536d2fc04286?tpId240&tqId2183007&ru%2…

2024 年合并 PDF 文件的免费 PDF 合并软件榜单

合并 PDF 是当今人们寻找的最重要的功能之一。在本文中&#xff0c;您将了解前五名的 PDF 合并软件以及详细的介绍&#xff0c;以便您选择最佳的。如果您想将所有重要信息都放在一个文件中&#xff0c;而不是在不同的文件中查找&#xff0c;那么合并 PDF 文件是必要的。通过这种…