在Python中使用套接字绑定和监听

2025 年 1 月 5 日 | 阅读 13 分钟

在 Python 中使用套接字建立网络通信时,理解绑定和监听过程至关重要。让我们深入研究具体细节。

网络是设备通过连接交换信息。由于套接字是在本地或广域网络上的设备之间以及在同一计算机上运行的不同进程之间发送消息的关键,因此它们是高效网络通信的重要组成部分。它们提供了一个低级接口,可以精确控制发送和接收的数据。

Binding and Listening with Sockets in Python

由于其低级设计,基于套接字通信构建的自定义协议可用于为特定用例创建高性能通信通道或低开销通信通道。因此,套接字在依赖即时消息或处理大量数据的实时客户端-服务器应用程序中非常有用。

理解:什么是套接字?

套接字是一个接口或网关,它促进运行在一台或多台机器上的各种进程之间的通信。在后一种情况下,讨论的是网络套接字。网络套接字抽象出连接管理。它们可以比作连接处理程序。

套接字是支持相同读写操作但通过网络传输所有数据的文件,尤其是在 Unix 系统中。当套接字处于监听或连接状态时,它总是绑定到一个 IP 地址和一个标识主机(计算机或设备)和进程的端口号。

套接字连接是如何工作的?

在计算机网络中,套接字充当网络上运行的两个程序之间通信的端点。让我们深入了解它的工作原理。

  • 套接字建立程序之间的双向通信链接。
  • 它通过创建命名联系点实现进程间通信 (IPC)。
  • 例如,可以将其视为两个端点之间的电话连接。

创建套接字

  • 首先,服务器创建一个套接字,将其连接到网络端口,并等待客户端联系它。
  • 客户端创建一个套接字并尝试连接到服务器套接字。

应对

  • 每个套接字都有一个由 IP 地址和端口号组成的特定地址。
  • IP 地址标识主机,端口号指定通信通道。

Socket 类型

这里描述了两种套接字

1. 数据报套接字

用于发送和接收数据包的无连接点。就像一个邮箱,投递到邮箱的数据被收集并发送到接收套接字。

2. 流套接字

提供面向连接、有序且唯一的数据流。没有记录边界;定义明确的连接创建、销毁和错误检测机制。可以将其比作电话通话:通常包括两端之间的数据转换的对话。

套接字 API 函数和方法

Python 提供了一个易于使用且可靠的 API,它直接映射到系统调用,相当于 C 语言调用。此模块的主要套接字 API 方法和函数包括:

socket()

此函数用于创建新套接字。使用的参数如下:

  • 地址族:- IPv4 使用 AF_INET,IPv6 使用 AF_INET6
  • 套接字类型:- TCP 使用 SOCK_STREAM,UDP 使用 SOCK_DGRAM

.bind()

可以使用 bind() 方法将套接字链接到本地计算机上的特定网络地址(IP 地址和端口号)。

.listen()

使用 bind() 绑定到地址的 TCP 套接字与此方法一起使用。将套接字置于监听状态会将其打开以接收新连接。

.connect()

连接到远程服务器时,TCP 客户端使用此方法。它请求服务器的地址以建立连接。

.accept()

监听 TCP 套接字使用此技术接受新的传入连接。它返回一个新套接字和客户端地址,并等待连接。

.recv()

此方法从已连接的套接字接收数据。它会阻塞,直到数据可用或连接关闭,并返回接收到的数据。

.send()

此方法通过已连接的套接字发送数据。它将要发送的数据作为参数。

.close()

此方法用于关闭套接字。一旦套接字关闭,就不能再用于发送或接收数据。

Binding and Listening with Sockets in Python

使用套接字的目的

在不同机器上运行的进程(应用程序)可以通过套接字相互通信。无论数据是在单个进程中、同一机器上的进程之间,甚至是在不同大陆之间交换,它们都使通过网络进行交换变得更容易。

创建

在 Python 中,我们导入套接字库来使用套接字。

使用 socket() 函数,我们创建一个套接字实例并将其传递给地址族(通常是 IPv4)和通信协议(通常是 TCP 或 UDP)。

代码

绑定和监听的工作原理?

  1. bind() 方法将服务器套接字绑定到特定的 IP 地址和端口。因此,它现在可以监听传入请求。
  2. 通过将服务器置于监听模式,listen() 方法使其能够接受传入连接。通过 accept() 方法建立与客户端的连接。

服务器配置

请参阅以下代码,了解如何配置服务器连接:

代码

绑定套接字

使用 bind() 方法将连接与特定的 IP 地址和端口号关联起来。此功能很重要,尤其是在处理服务器连接时,因为它确保服务器正确维护指定的 IP 地址和端口以处理传入查询。

代码

监听模式

服务器阻塞后,它会触发 listen() 方法切换到主动监视传入连接的状态。因此,服务器可以主动监视客户端发起的新连接。listen() 参数中指定了排队连接的最大限制。

代码

接受连接

使用 accept() 函数与客户端建立链接。服务器接受来自客户端的链接,为该客户端提供另一个套接字以用于通信。

代码

什么是 TCP 套接字?

在 TCP/IP 应用程序中,TCP 套接字是一个基本概念。它充当两个网络运行程序之间的通信端点。想象它是一个电话连接,允许两个端点之间交换数据。

SOCK_STREAM (TCP)

它连接到 TCP (传输控制协议) 系统。提供发送和接收数据的安全方法。需要连接才能传输数据。

优点

  • 可靠性:检测到丢失的数据包后重新传输。
  • 数据顺序一致性由有序数据传输确保。

示例

让我们创建一个连接到 google.com 端口 80 的 Python TCP 客户端套接字。

SOCK_DGRAM (UDP)

与 UDP 协议关联。它支持无需连接的通信。

异步数据报携带数据。UDP 是 Internet 协议套件中的传输层协议。与 TCP 不同,它不可靠且无连接。

数据传输前无需事先建立连接。

为什么选择 UDP?

以下是选择用户数据报协议的一些关键原因:

  • 低延迟: UDP 有助于在网络上建立低延迟连接。
  • 容错: 它允许丢弃数据包而不是延迟处理。
  • 无错误检查: 与 TCP 不同,UDP 不执行错误检查。
  • 高效:由于其简单性,节省了带宽。
  • UDP 报头: UDP 报头是固定的 8 字节结构。
  • 源端口: 标识发送方的端口。
  • 目的端口: 标识接收方的端口。
  • 长度: UDP 数据包的总长度(报头 + 数据)。
  • 校验和: 可选,用于错误检测。

UDP 的应用

  1. 由于其数据包交换支持,适用于多播。
  2. 用于路由更新协议,例如 RIP。

实时应用

  1. 在线游戏:低延迟和高速通信。
  2. 语音和视频通信。
  3. 现场会议。

示例

数据报套接字用于通过 UDP 进行通信。数据报套接字使跨 Internet 的数据包发送和接收成为可能。

请注意服务器建立“监听”套接字所做的以下 API 调用,从左上角的列开始。

为了连接到服务器并开始三次握手,客户端调用函数 .connect()。握手阶段对于客户端到达服务器反之亦然至关重要,因为它保证连接的两端在网络上都是可达的。只有一个主机、客户端或服务器能够与另一个通信。

中间是往返部分,其中 send() 和 recv() 调用在客户端和服务器之间传输数据。客户端和服务器在底部关闭各自的套接字。

回显客户端和服务器

一个称为回显服务器的简单程序接收来自客户端的数据并将其回显给客户端。换句话说,服务器将收到的所有内容都传回给客户端。它类似于一个数字镜子!

回显服务器

这是一个简单的 Python 回显服务器实现示例:

代码

输出

Server listening on 127.0.0.1:12345

服务器使用给定的地址和端口进行监听。建立连接后,客户端接收数据,将其回显,然后结束交换。

回显客户端

让我们创建一个简单的回显客户端:

代码

输出

Enter a message: Hello
Echoed message: Hello

客户端和服务器利用相同的位置和端口建立连接。一旦消息被传输并接收到回显,它们就会终止通信。

上述代码的解释

  • import socket: 它从 Python socket 模块导入低级网络接口。
  • def echo_client(): 这定义了由函数表示的客户端功能。
  • port = 12345 和 host = "127.0.0.1": 这些行指定了客户端将连接到的主机(此处为 localhost)和端口号。客户端连接到它运行的同一主机 (127.0.0.1) 上的端口 12345。
  • client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM): 此代码行创建一个新的套接字对象。提及 AF_INET 表示我们正在使用 IPv4 地址,而 socket.SOCK_STREAM 指定表示该套接字是 TCP 套接字。
  • connect((host, port)): 它建立与由主机和端口指定的服务器的连接。
  • message = input("输入消息: "): 此代码行创建一个输入区域,用于输入用户的值。
  • sendall(message.encode("utf-8")): 常见的 UTF-8 编码用于在网络浏览器中将文本数据发送到服务器。
  • echoed_message = client_socket.recv(1024).decode("utf-8"): 此代码从服务器获取回显传输。它从服务器检索 1024 个数据单元,以 UTF-8 编码格式解码。然后,将它们保存在 echoed_message 容器中。
  • print(f"回显消息: {echoed_message}"): 此代码帮助我们在控制台上显示回显消息。
  • close(): 此代码用于关闭服务器连接。
  • if __name__ == "__main__": 此行验证脚本是否作为主程序执行。
  • echo_client(): 如果脚本作为主程序运行,则此特定行将触发 echo_client() 函数的调用,从而执行客户端的功能。

运行回显服务器和客户端

要运行客户端和服务器并查看服务器接收到的客户端消息,请按照以下步骤操作:

  • 打开两个终端或命令提示符。
  • 在一个终端中,运行 python echo_server.py
  • 在第二个终端中,运行 python echo_client.py
  • 现在,在客户端窗口中输入消息,您可以看到它被服务器窗口回显回来。

查看输出

运行 python echo_server.py 后,您可以看到输出:

Server listening on 127.0.0.1:12345

运行 python echo_client.py 后,您将获得输出:

Enter a message: hi
Echoed message: hi

查看套接字状态

让我们使用 netstat 命令查看运行主机上套接字的当前状态。您可以通过输入此命令查看 Mac、Linux 和 Windows 套接字状态。

netstat 命令用于查看计算机监听的活动 TCP 连接。运行 netstat 后,您应该看到以下输出:

输出

Binding and Listening with Sockets in Python

您可以看到本地地址是 127.0.0.1:12345。当 echo_server.py 中 HOST 的值为“ ”而不是 HOST = "127.0.0.1" 时,输出将如下所示:

输出

Echo server listening on: 12345

客户端和服务器如何通信?

让我们看看客户端和服务器如何相互通信。

使用回环接口(IPv4 地址 127.0.0.1 或 IPv6 地址 ::1)时,数据永远不会离开主机或与外部网络接触。上图中主机内部显示了回环接口。这说明了回环接口的内部结构,以及通过它传输的连接和数据是主机本地的。因此,IP 地址 127.0.0.1 或 ::1 和回环接口也称为“localhost”。

Binding and Listening with Sockets in Python

应用程序使用回环接口来实现安全性、网络隔离以及与其他主机进程的通信。它没有暴露,因为它是内部的,只能从主机内部访问。

如果您有一个使用私有数据库的应用程序服务器,则可以观察到这一点。如果其他服务器不使用该数据库,则它很可能被设置为仅通过回环接口接受连接。如果发生这种情况,网络上的其他主机无法连接到它。

如果您在应用程序中使用的 IP 地址不是 127.0.0.1 或 ::1,则它很可能与连接到外部网络的以太网接口相关联。这是您进入“localhost”领域之外的主机的入口。

Binding and Listening with Sockets in Python

历史

套接字历史悠久。它们始于 1971 年的 ARPANET,并于 1983 年,Berkeley 软件发行版 (BSD) 操作系统引入了 Berkeley 套接字,一个应用程序编程接口。

网络编程随着 1990 年代互联网的兴起而激增,这与万维网的出现不谋而合。利用套接字和新连接网络的应用程序超越了网络服务器和浏览器。各种规模的客户端和服务器应用程序变得司空见惯。

尽管新协议已经出现,并且套接字 API 使用的基础协议随着时间的推移而改变,但低级 API 尚未改变。

故障排除方法

有时,某些功能不起作用,您会寻找它们。在这里,我们将讨论一些重要的调试器,它们将使您能够很好地处理源代码部分。

在采用这些故障排除方法之前,请确保您已阅读每个函数和方法的文档。并非所有事情都与源代码有关。可能是另一台主机、客户端或服务器,而源代码是准确的。也可能是网络。也许路由器、防火墙或其他网络设备正在进行中间人攻击。

这些类型的问题需要更多工具。下面列出了一些可能有用的实用程序和工具,或者至少提供了一些提示。

Ping

使用 ICMP 回显请求,ping 可以确定主机是否已启动并连接到网络。它独立于任何主机应用程序运行,因为它直接与操作系统的 TCP/IP 协议栈接口。

分隔您和另一台主机的防火墙可能会阻止 ping 请求的实现。这是由某些防火墙管理员制定的策略强制执行的。理论上,他们希望阻止他们的主机被发现。在这种情况下,请确保您添加的允许主机之间通信的防火墙规则也允许 ICMP 在它们之间通过。

Ping 使用 ICMP 协议,TCP 和其他低级协议也使用该协议来传输错误消息。这可能会导致您遇到任何奇怪的行为或缓慢的连接。

netstat

netstat 命令提供有关网络连接、正在使用的端口和相关进程的宝贵信息。Netstat 是诊断网络复杂性和理解网络操作的强大工具,具有巨大的潜力。深入研究其广泛的选项和变量,根据您的具体要求进行调整。看哪,看哪,著名 netstat 命令的众多应用!

查看所有活动连接: 如果您想获取所有当前网络连接(包括打开和关闭的套接字)的完整列表,可以使用以下命令:

按网络接口过滤: 如果您希望查看网络连接列表,可以选择运行以下命令:


Binding and Listening with Sockets in Python

Wireshark

Wireshark 是一款作为开源运动的一部分创建的软件,它一丝不苟地记录和展示通过网络的信息。Wireshark 允许网络技术人员和系统管理员通过分析网络通信来查明操作挑战。它有助于发现数据丢失和拥塞点等问题。

  • 安全分析: 网络安全专业人员使用 Wireshark 跟踪连接、分析可疑网络事务并识别网络活动的突然增加。
  • 软件测试: Wireshark 是软件开发人员和质量保证专业人员用来验证网络相关功能、观察应用程序交互和评估软件性能的工具。

如何使用?

下载并安装

  • 访问 Wireshark 基金会网站,获取适用于 Windows 或 macOS 的最新稳定版本。
  • 在 Windows 安装过程中(如果提示),安装 WinPcap 或 Npcap 以进行实时数据捕获。
  • 以管理员模式启动 Wireshark。
  • 此外,Linux 和其他类 UNIX 平台也可以使用它。

捕获数据包

  • 启动 Wireshark 并选择要监视的网络接口。
  • 开始捕获数据包。
  • 保存捕获以进行分析。
  • 需要时停止捕获。

查看和分析数据包内容

  • Wireshark 的界面包括数据包列表窗格(顶部部分)和详细信息窗格(中间部分)。
  • 探索捕获的数据包、剖析协议并分析网络行为。

结论

使用套接字进行绑定和监听对于在 Python 中创建网络服务器至关重要。绑定将服务器与特定的 IP 和端口关联起来,使其能够监听传入请求。listen() 方法将服务器置于监听模式,使其能够接受连接。这些步骤促进了网络节点之间的通信,使套接字编程对于网络管理员和开发人员来说必不可少。