练习题:37

目录

Python题目

题目

题目分析

套接字概念剖析

通信原理分析

服务器 - 客户端连接建立过程:

基于套接字通信的底层机制:

代码实现

基于 TCP 的简单服务器 - 客户端通信示例

服务器端代码(tcp_server.py)

客户端代码(tcp_client.py)

基于 UDP 的简单服务器 - 客户端通信示例

服务器端代码(udp_server.py)

客户端代码(udp_client.py)

代码解释

基于 TCP 的代码解释

服务器端

导入模块与创建套接字对象:

绑定 IP 地址和端口号并监听:

接受客户端连接并处理通信:

客户端

导入模块与创建套接字对象:

连接服务器并发送接收消息:

基于 UDP 的代码解释

服务器端

导入模块与创建套接字对象:

绑定 IP 地址和端口号并监听:

接收并处理客户端消息:

客户端

导入模块与创建套接字对象:

发送消息并接收回复:

运行思路

基于 TCP 的代码分析

服务器端代码分析

导入模块与创建套接字对象:

绑定 IP 地址和端口号并监听:

接受客户端连接并处理通信:

客户端代码分析

导入模块与创建套接字对象:

连接服务器并发送接收消息:

基于 UDP 的代码分析

服务器端代码分析

导入模块与创建套接字对象:

绑定 IP 地址和端口号并监听:

接收并处理客户端消息:

客户端代码分析

导入模块与创建套接字对象:

发送消息并接收回复:

结束语

Python题目

题目

套接字是什么?为什么在服务器端宇客户端建立了套接字就可以通信了?

题目分析

  • 套接字概念剖析

    • 定义理解:套接字(Socket)是网络通信的基石,它是一种软件抽象层,用于在不同主机之间的进程进行通信。可以把套接字想象成是电话插孔,不同主机上的进程通过这个 “插孔”(套接字)来建立连接,就像两部电话通过插孔和线路连接起来进行通话一样。在网络编程中,它屏蔽了底层网络协议(如 TCP/IP 协议族)的复杂细节,为程序员提供了一个相对简单的接口来进行网络通信。
    • 类型区分:主要分为流套接字(Stream Socket,基于 TCP 协议)和数据报套接字(Datagram Socket,基于 UDP 协议)。流套接字提供面向连接、可靠的字节流服务,就像打电话一样,通信双方先建立连接,然后按顺序传输数据,数据不会丢失或乱序。数据报套接字则是无连接的、不可靠的通信方式,类似于发送短信,消息被封装成一个个独立的数据报发送,不保证数据一定能到达,也不保证顺序。
  • 通信原理分析

    • 服务器 - 客户端连接建立过程
      • 服务器端套接字创建与监听:服务器首先创建一个套接字,这个套接字绑定到一个特定的 IP 地址和端口号(IP 地址用于标识服务器在网络中的位置,端口号用于区分不同的服务)。然后,服务器通过这个套接字开始监听客户端的连接请求。例如,一个 Web 服务器监听在 80 端口(HTTP 服务默认端口)等待客户端浏览器的连接请求。
      • 客户端套接字创建与连接请求:客户端同样创建一个套接字,然后使用服务器的 IP 地址和端口号向服务器发送连接请求。这个请求通过网络传输,当服务器监听到这个请求后,就会接受这个请求,从而在服务器和客户端之间建立起一个连接。
    • 基于套接字通信的底层机制
      • 协议支持:一旦建立连接(对于流套接字),TCP/IP 协议就会确保数据在两个套接字之间可靠地传输。它通过一系列机制,如三次握手建立连接、数据确认和重传、流量控制等来保证数据的完整性和顺序性。例如,当客户端发送一个数据包时,TCP 协议会在数据包中添加序列号等信息,服务器收到后会发送确认信息,这样就保证了数据传输的可靠性。
      • 数据传输通道形成:套接字在连接建立后,就像在服务器和客户端之间建立了一条虚拟的数据传输通道。双方可以通过这个通道发送和接收数据,数据以字节流(对于流套接字)或数据报(对于数据报套接字)的形式在通道中传输。例如,客户端可以将用户输入的信息通过套接字发送给服务器,服务器接收到数据后进行处理,并将结果通过套接字返回给客户端。

代码实现

基于 TCP 的简单服务器 - 客户端通信示例

服务器端代码(tcp_server.py
import socket# 创建套接字对象,AF_INET表示使用IPv4地址族,SOCK_STREAM表示使用TCP协议(流套接字)
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 绑定IP地址和端口号,这里使用本地回环地址127.0.0.1和端口8888
server_address = ('127.0.0.1', 8888)
server_socket.bind(server_address)# 开始监听,参数5表示允许的最大连接数
server_socket.listen(5)
print('服务器已启动,正在监听端口8888...')while True:# 接受客户端连接,返回一个新的套接字对象(用于与该客户端通信)和客户端地址client_socket, client_address = server_socket.accept()print(f'接受来自 {client_address} 的连接')try:# 接收客户端发送的数据,最多接收1024字节data = client_socket.recv(1024)if data:message = data.decode('utf-8')print(f'从客户端收到消息: {message}')# 处理客户端消息,这里简单将消息转换为大写后返回给客户端response = message.upper()client_socket.send(response.encode('utf-8'))print(f'已将处理后的消息发送回客户端')except:print('接收或发送数据时出现错误')finally:# 关闭与该客户端的套接字连接client_socket.close()
客户端代码(tcp_client.py
import socket# 创建套接字对象,同样使用IPv4地址族和TCP协议
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 服务器的IP地址和端口号,要与服务器端绑定的一致
server_address = ('127.0.0.1', 8888)try:# 连接服务器client_socket.connect(server_address)message = "Hello, Server!"# 向服务器发送消息,需先将字符串编码为字节流client_socket.send(message.encode('utf-8'))print(f'已向服务器发送消息: {message}')# 接收服务器返回的消息,最多接收1024字节data = client_socket.recv(1024)if data:response = data.decode('utf-8')print(f'从服务器收到回复: {response}')
except:print('连接服务器或通信过程中出现错误')
finally:# 关闭客户端套接字client_socket.close()

基于 UDP 的简单服务器 - 客户端通信示例

服务器端代码(udp_server.py
import socket# 创建套接字对象,AF_INET表示使用IPv4地址族,SOCK_DGRAM表示使用UDP协议(数据报套接字)
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)# 绑定IP地址和端口号,这里使用本地回环地址127.0.0.1和端口9999
server_address = ('127.0.0.1', 9999)
server_socket.bind(server_address)print('UDP服务器已启动,正在监听端口9999...')while True:# 接收客户端发送的数据和客户端地址,最多接收1024字节data, client_address = server_socket.recvfrom(1024)if data:message = data.decode('utf-8')print(f'从客户端收到消息: {message}')# 处理客户端消息,这里简单将消息转换为大写后返回给客户端response = message.upper()server_socket.sendto(response.encode('utf-8'), client_address)print(f'已将处理后的消息发送回客户端')
客户端代码(udp_client.py
import socket# 创建套接字对象,使用IPv4地址族和UDP协议
client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)# 服务器的IP地址和端口号,要与服务器端绑定的一致
server_address = ('127.0.0.1', 9999)message = "Hello, UDP Server!"
# 向服务器发送消息,需先将字符串编码为字节流
client_socket.sendto(message.encode('utf-8'), server_address)
print(f'已向服务器发送消息: {message}')# 接收服务器返回的消息,最多接收1024字节
data, server_address = client_socket.recvfrom(1024)
if data:response = data.decode('utf-8')print(f'从服务器收到回复: {response}')# 关闭客户端套接字
client_socket.close()

代码解释

基于 TCP 的代码解释

服务器端
  • 导入模块与创建套接字对象
import socketserver_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  • 首先通过 import socket 导入 Python 的 socket 模块,该模块提供了进行网络套接字编程所需的各种函数和类等资源。
  • 然后调用 socket.socket() 函数创建一个套接字对象 server_socket,参数 socket.AF_INET 表示使用 IPv4 地址族,socket.SOCK_STREAM 表示使用 TCP 协议(即创建的是流套接字),这个套接字将作为服务器与客户端进行通信的基础接口。
  • 绑定 IP 地址和端口号并监听
server_address = ('127.0.0.1', 8888)
server_socket.bind(server_address)
server_socket.listen(5)
print('服务器已启动,正在监听端口8888...')
  • 定义 server_address 元组,其中第一个元素 '127.0.0.1' 是 IP 地址,这里使用本地回环地址(常用于在本地机器上测试网络程序,意味着只有本机上的程序可以访问该服务器),第二个元素 8888 是端口号(可以根据实际需求选择合适的未被占用的端口)。
  • 调用 server_socket.bind(server_address) 方法将创建好的套接字绑定到指定的 IP 地址和端口号上,这样服务器就在这个网络端点上等待客户端的连接请求了。
  • 接着调用 server_socket.listen(5) 方法开始监听客户端的连接请求,参数 5 表示服务器允许的最大连接数,即同时可以有多少个客户端连接到服务器等待处理。
  • 接受客户端连接并处理通信
while True:client_socket, client_address = server_socket.accept()print(f'接受来自 {client_address} 的连接')try:data = client_socket.recv(1024)if data:message = data.decode('utf-8')print(f'从客户端收到消息: {message}')response = message.upper()client_socket.send(response.encode('utf-8'))print(f'已将处理后的消息发送回客户端')except:print('接收或发送数据时出现错误')finally:client_socket.close()
  • 使用 while True 循环使得服务器可以持续处理多个客户端的连接请求。在循环内部,调用 server_socket.accept() 方法,该方法会阻塞程序执行,直到有客户端连接过来,当有客户端连接时,它会返回一个新的套接字对象 client_socket(这个套接字专门用于与该客户端进行后续的通信)以及客户端的地址 client_address(包含客户端的 IP 地址和端口号)。
  • 进入 try 块尝试接收客户端发送的数据,调用 client_socket.recv(1024) 方法从与客户端连接的套接字接收数据,参数 1024 表示最多接收 1024 字节的数据。如果接收到了数据,通过 data.decode('utf-8') 将接收到的字节数据解码为字符串形式赋值给 message 变量,并打印出来。
  • 接着对收到的消息进行处理,这里简单地将消息转换为大写形式,赋值给 response 变量,然后调用 client_socket.send(response.encode('utf-8')) 方法将处理后的消息编码为字节流并发送回客户端,同时打印发送提示信息。
  • 如果在接收或发送数据过程中出现错误,except 块会捕获异常并打印错误提示信息。
  • 无论是否出现错误,在 finally 块中都会调用 client_socket.close() 方法关闭与当前客户端的套接字连接,释放相关资源,准备处理下一个客户端的连接。
客户端
  • 导入模块与创建套接字对象
import socketclient_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  • 同样先通过 import socket 导入 socket 模块,然后调用 socket.socket() 函数创建一个套接字对象 client_socket,使用的参数也是 socket.AF_INET(IPv4 地址族)和 socket.SOCK_STREAM(TCP 协议),用于与服务器进行通信。
  • 连接服务器并发送接收消息
server_address = ('127.0.0.1', 8888)
try:client_socket.connect(server_address)message = "Hello, Server!"client_socket.send(message.encode('utf-8'))print(f'已向服务器发送消息: {message}')data = client_socket.recv(1024)if data:response = data.decode('utf-8')print(f'从服务器收到回复: {response}')
except:print('连接服务器或通信过程中出现错误')
finally:client_socket.close()
  • 定义 server_address 元组,指定要连接的服务器的 IP 地址(这里同样是本地回环地址 127.0.0.1)和端口号(8888),要与服务器端绑定的地址和端口一致。
  • 调用 client_socket.connect(server_address) 方法向服务器发起连接请求,如果连接成功,程序继续往下执行。
  • 定义要发送给服务器的消息 message,然后调用 client_socket.send(message.encode('utf-8')) 方法将消息编码为字节流并发送给服务器,同时打印发送提示信息。
  • 接着调用 client_socket.recv(1024) 方法从服务器接收回复消息,最多接收 1024 字节的数据,若接收到了数据,将其解码为字符串形式赋值给 response 变量,并打印出来。
  • 如果在连接服务器或通信过程中出现错误,except 块会捕获异常并打印相应的错误提示信息。
  • 最后,在 finally 块中调用 client_socket.close() 方法关闭客户端套接字,释放资源。

基于 UDP 的代码解释

服务器端
  • 导入模块与创建套接字对象
import socketserver_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  • 还是先通过 import socket 导入 socket 模块,然后调用 socket.socket() 函数创建套接字对象 server_socket,这次参数使用 socket.AF_INET(IPv4 地址族)和 socket.SOCK_DGRAM(表示使用 UDP 协议,即创建的数据报套接字),用于基于 UDP 协议进行通信。
  • 绑定 IP 地址和端口号并监听
server_address = ('127.0.0.1', 9999)
server_socket.bind(server_address)
print('UDP服务器已启动,正在监听端口9999...')
  • 定义 server_address 元组,包含本地回环地址 '127.0.0.1' 和端口号 9999,用于指定服务器监听的网络端点。
  • 调用 server_socket.bind(server_address) 方法将套接字绑定到这个地址和端口上,使服务器可以在该端点接收客户端发送的数据报。
  • 接收并处理客户端消息
while True:data, client_address = server_socket.recvfrom(1024)if data:message = data.decode('utf-8')print(f'从客户端收到消息: {message}')response = message.upper()server_socket.sendto(response.encode('utf-8'), client_address)print(f'已将处理后的消息发送回客户端')
  • 通过 while True 循环持续等待接收客户端发送的数据报。在循环内,调用 server_socket.recvfrom(1024) 方法接收客户端发送的数据报,这个方法会阻塞程序执行,直到接收到数据报为止,它返回接收到的数据(字节形式)和客户端的地址(包含客户端的 IP 地址和端口号)。
  • 如果接收到了数据,将其解码为字符串形式赋值给 message 变量并打印出来。
  • 对消息进行处理(这里同样是转换为大写形式),得到 response 变量,然后调用 server_socket.sendto(response.encode('utf-8'), client_address) 方法将处理后的消息编码为字节流,并根据客户端的地址发送回客户端,同时打印发送提示信息。
客户端
  • 导入模块与创建套接字对象
import socketclient_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  • 导入 socket 模块后创建一个套接字对象 client_socket,使用 socket.AF_INET(IPv4 地址族)和 socket.SOCK_DGRAM(UDP 协议)参数,用于向服务器发送和接收数据报。
  • 发送消息并接收回复
server_address = ('127.0.0.1', 9999)
message = "Hello, UDP Server!"
client_socket.sendto(message.encode('utf-8'), server_address)
print(f'已向服务器发送消息: {message}')
data, server_address = client_socket.recvfrom(1024)
if data:response = data.decode('utf-8')print(f'从服务器收到回复: {response}')
client_socket.close()
  • 定义 server_address 元组,指定服务器的 IP 地址(127.0.0.1)和端口号(9999)。
  • 定义要发送给服务器的消息 message,然后调用 client_socket.sendto(message.encode('utf-8'), server_address) 方法将消息编码为字节流,并按照指定的服务器地址发送出去,同时打印发送提示信息。
  • 调用 client_socket.recvfrom(1024) 方法等待接收服务器返回的数据报,接收到后将数据解码为字符串赋值给 response 变量并打印出来。
  • 最后调用 client_socket.close() 方法关闭客户端套接字,释放资源。

运行思路

基于 TCP 的代码分析

服务器端代码分析
  • 导入模块与创建套接字对象
import socketserver_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  • 导入模块import socket 语句将 Python 标准库中的 socket 模块引入程序,该模块提供了操作网络套接字的各种函数、类等资源,是实现网络通信编程的基础。若没有正确导入此模块,后续使用套接字相关功能时会引发 ModuleNotFoundError 异常,导致程序无法继续运行。
  • 创建套接字对象socket.socket(socket.AF_INET, socket.SOCK_STREAM) 调用创建了一个套接字对象 server_socket。其中,socket.AF_INET 表示选用 IPv4 地址族,意味着这个套接字将基于 IPv4 网络进行通信,适用于大多数常见的网络环境;socket.SOCK_STREAM 表明创建的是流套接字,它基于 TCP 协议,提供面向连接、可靠的字节流通信服务,就像打电话一样,通信双方先建立稳定连接后再传输数据,且能保证数据的完整性和顺序性。
  • 绑定 IP 地址和端口号并监听
server_address = ('127.0.0.1', 8888)
server_socket.bind(server_address)
server_socket.listen(5)
print('服务器已启动,正在监听端口8888...')
  • 定义服务器地址server_address = ('127.0.0.1', 8888) 创建了一个包含 IP 地址和端口号的元组。127.0.0.1 是本地回环地址,代表本机,常用于在本地进行网络程序的测试,只有本机上的其他程序可以通过这个地址访问该服务器;8888 是端口号,它用于在网络通信中区分不同的服务或应用程序,取值范围是 0 到 65535,这里选择 8888 作为自定义的服务端口(需确保该端口未被其他程序占用)。
  • 绑定套接字到地址server_socket.bind(server_address) 方法将之前创建的 server_socket 套接字绑定到指定的 server_address 上,使得服务器在网络中通过这个特定的 IP 地址和端口号来接收客户端的连接请求。若绑定的端口已被其他程序占用,会抛出 socket.error 异常,提示地址已在使用中。
  • 开始监听客户端连接server_socket.listen(5) 调用让服务器套接字进入监听状态,参数 5 表示服务器允许的最大连接数,即同时可以有最多 5 个客户端连接到服务器并处于等待处理的状态。一旦进入监听状态,服务器就开始等待客户端的连接请求,此时程序会阻塞在 accept 方法(后续调用处),直到有客户端发起连接。
  • 接受客户端连接并处理通信
while True:client_socket, client_address = server_socket.accept()print(f'接受来自 {client_address} 的连接')try:data = client_socket.recv(1024)if data:message = data.decode('utf-8')print(f'从客户端收到消息: {message}')response = message.upper()client_socket.send(response.encode('utf-8'))print(f'已将处理后的消息发送回客户端')except:print('接收或发送数据时出现错误')finally:client_socket.close()
  • 循环接受客户端连接while True 构建了一个无限循环,使得服务器能够持续不断地处理多个客户端的连接请求,只要服务器在运行,就会一直等待并处理新的连接。
  • 接受客户端连接client_socket, client_address = server_socket.accept() 这行代码是整个服务器通信流程的关键部分,accept 方法会阻塞程序执行,直到有客户端连接过来。当有客户端发起连接时,它会返回两个值:一个新的套接字对象 client_socket(这个套接字专门用于与该客户端进行后续的一对一通信,与之前用于监听的 server_socket 不同)和客户端的地址 client_address(包含客户端的 IP 地址和端口号,以元组形式呈现,例如 ('192.168.1.100', 56789)),通过打印 client_address 可以知晓客户端的来源信息。
  • 接收客户端数据:在 try 块内,data = client_socket.recv(1024) 调用尝试从与客户端连接的 client_socket 套接字接收数据,参数 1024 表示最多接收 1024 字节的数据,这是一种常见的设置,可根据实际需求调整大小。如果成功接收到了数据(即 data 不为空),message = data.decode('utf-8') 会将接收到的字节数据按照 UTF-8 编码格式解码为字符串形式,赋值给 message 变量,然后通过 print(f'从客户端收到消息: {message}') 将消息内容打印出来,方便查看客户端发送的内容。
  • 处理并返回数据:接着,response = message.upper() 将接收到的消息转换为大写形式,作为对客户端的响应内容。然后,client_socket.send(response.encode('utf-8')) 调用把处理后的响应消息 response 先编码为字节流(使用 UTF-8 编码,确保与接收时的解码格式一致),再通过 client_socket 发送回客户端,同时通过 print(f'已将处理后的消息发送回客户端') 打印发送提示信息,告知服务器端已成功发送响应。
  • 异常处理与资源释放:如果在接收或发送数据过程中出现任何错误(如网络中断、客户端意外关闭连接等),except 块会捕获异常并通过 print('接收或发送数据时出现错误') 打印相应的错误提示信息,便于排查问题。无论是否出现错误,在 finally 块中都会调用 client_socket.close() 方法关闭与当前客户端的套接字连接,释放相关资源,避免资源泄漏,并准备好处理下一个客户端的连接请求。
客户端代码分析
  • 导入模块与创建套接字对象
import socketclient_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  • 导入模块:同服务器端一样,通过 import socket 导入 socket 模块,为后续创建套接字和进行网络通信操作提供必要的功能支持。
  • 创建套接字对象client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 创建了一个客户端使用的套接字对象 client_socket,同样使用 socket.AF_INET(IPv4 地址族)和 socket.SOCK_STREAM(TCP 协议)参数,这使得客户端创建的套接字与服务器端创建的用于监听和接受连接的套接字类型匹配,能够基于 TCP 协议建立可靠的连接进行通信。
  • 连接服务器并发送接收消息
server_address = ('127.0.0.1', 8888)
try:client_socket.connect(server_address)message = "Hello, Server!"client_socket.send(message.encode('utf-8'))print(f'已向服务器发送消息: {message}')data = client_socket.recv(1024)if data:response = data.decode('utf-8')print(f'从服务器收到回复: {response}')
except:print('连接服务器或通信过程中出现错误')
finally:client_socket.close()
  • 定义服务器地址server_address = ('127.0.0.1', 8888) 定义了要连接的服务器的 IP 地址和端口号,这里的地址和端口号必须与服务器端绑定并监听的地址端口完全一致,否则客户端无法正确连接到服务器。
  • 连接服务器client_socket.connect(server_address) 调用尝试向指定的 server_address 对应的服务器发起连接请求,若服务器正常监听且网络可达,连接会成功建立,程序继续往下执行;若连接出现问题(如服务器未启动、网络故障、端口号错误等),会抛出异常,被后续的 except 块捕获处理。
  • 发送消息给服务器:成功连接服务器后,定义要发送的消息 message = "Hello, Server!",然后通过 client_socket.send(message.encode('utf-8')) 调用将消息先编码为字节流(采用 UTF-8 编码格式),再通过 client_socket 发送给服务器,同时通过 print(f'已向服务器发送消息: {message}') 打印发送提示信息,方便查看发送情况。
  • 接收服务器回复:接着调用 client_socket.recv(1024) 尝试从服务器接收回复消息,最多接收 1024 字节的数据,若接收到了数据(即 data 不为空),则通过 response = data.decode('utf-8') 将接收到的字节数据按照 UTF-8 编码格式解码为字符串形式,赋值给 response 变量,并通过 print(f'从服务器收到回复: {response}') 打印出服务器回复的内容,实现客户端与服务器之间的消息交互。
  • 异常处理与资源释放:在整个连接服务器和通信过程中,如果出现任何错误(如连接超时、服务器意外关闭连接等),except 块会捕获异常并通过 print('连接服务器或通信过程中出现错误') 打印相应的错误提示信息,有助于定位问题所在。最后,无论通信是否成功,在 finally 块中都会调用 client_socket.close() 方法关闭客户端套接字,释放相关资源,确保程序的资源管理规范和正常结束。

基于 UDP 的代码分析

服务器端代码分析
  • 导入模块与创建套接字对象
import socketserver_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  • 导入模块:通过 import socket 导入 socket 模块,为后续创建 UDP 套接字及相关网络通信操作提供功能支持,若模块导入失败会导致程序无法使用套接字相关功能。
  • 创建套接字对象server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 创建了一个基于 UDP 协议的数据报套接字对象 server_socket,这里使用 socket.AF_INET 表示 IPv4 地址族,说明基于 IPv4 网络进行通信,而 socket.SOCK_DGRAM 明确了该套接字采用 UDP 协议,UDP 协议是一种无连接、不可靠的通信方式,类似于发送短信,数据被封装成独立的数据报进行发送,不保证数据一定能到达目的地,也不保证数据的顺序性,但它具有开销小、传输速度快的特点,适用于一些对实时性要求较高、对数据完整性要求相对不那么严格的场景。
  • 绑定 IP 地址和端口号并监听
server_address = ('127.0.0.1', 9999)
server_socket.bind(server_address)
print('UDP服务器已启动,正在监听端口9999...')
  • 定义服务器地址server_address = ('127.0.0.1', 9999) 创建了一个包含 IP 地址(本地回环地址 127.0.0.1,用于在本地进行测试,只有本机上的程序能访问)和端口号 9999 的元组,9999 作为服务器监听的端口号,需确保该端口未被其他程序占用,否则绑定会失败并抛出异常。
  • 绑定套接字到地址server_socket.bind(server_address) 方法将创建好的 server_socket 套接字绑定到指定的 server_address 上,使得服务器在该网络端点上等待接收客户端发送的数据报,一旦绑定成功,服务器就开始在这个端口监听客户端的数据发送。
  • 接收并处理客户端消息
while True:data, client_address = server_socket.recvfrom(1024)if data:message = data.decode('utf-8')print(f'从客户端收到消息: {message}')response = message.upper()server_socket.sendto(response.encode('utf-8'), client_address)print(f'已将处理后的消息发送回客户端')
  • 循环接收客户端数据报while True 构建了一个无限循环,让服务器持续处于监听状态,能够不断接收不同客户端发送的数据报,只要服务器运行,就会一直等待并处理新收到的数据。
  • 接收客户端数据报及地址data, client_address = server_socket.recvfrom(1024) 调用是 UDP 服务器接收数据报的关键操作,它会阻塞程序执行,直到接收到客户端发送的数据报为止,然后返回接收到的数据(字节形式)和客户端的地址(包含客户端的 IP 地址和端口号,以元组形式呈现)。参数 1024 表示最多接收 1024 字节的数据,可根据实际需求调整这个值。
  • 处理并返回数据报:如果接收到了数据(即 data 不为空),首先通过 message = data.decode('utf-8') 将接收到的字节数据按照 UTF-8 编码格式解码为字符串形式,赋值给 message 变量,并通过 print(f'从客户端收到消息: {message}') 打印出客户端发送的消息内容。接着,对消息进行处理(这里同样是转换为大写形式),得到 response 变量,然后调用 server_socket.sendto(response.encode('utf-8'), client_address) 方法将处理后的消息 response 先编码为字节流(使用 UTF-8 编码),再根据接收到的客户端地址 client_address 将数据报发送回客户端,同时通过 print(f'已将处理后的消息发送回客户端') 打印发送提示信息,告知服务器已成功回复客户端。
客户端代码分析
  • 导入模块与创建套接字对象
import socketclient_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  • 导入模块:和前面一样,通过 import socket 导入 socket 模块,以便后续使用套接字相关的功能来创建 UDP 套接字并进行通信操作。
  • 创建套接字对象client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 创建了一个客户端使用的基于 UDP 协议的数据报套接字对象 client_socket,使用 socket.AF_INET(IPv4 地址族)和 socket.SOCK_DGRAM(UDP 协议)参数,使其能够与服务器端创建的 UDP 套接字进行相应的数据报通信。
  • 发送消息并接收回复
server_address = ('127.0.0.1', 9999)
message = "Hello, UDP Server!"
client_socket.sendto(message.encode('utf-8'), server_address)
print(f'已向服务器发送消息: {message}')
data, server_address = client_socket.recvfrom(1024)
if data:response = data.decode('utf-8')print(f'从服务器收到回复: {response}')
client_socket.close()
  • 定义服务器地址server_address = ('127.0.0.1', 9999) 定义了要发送数据报的目标服务器的 IP 地址和端口号,该地址必须与服务器端绑定并监听的地址端口一致,这样才能确保数据报能准确发送到服务器。
  • 发送消息给服务器:定义要发送的消息 message = "Hello, UDP Server!",然后通过 client_socket.sendto(message.encode('utf-8'), server_address) 调用将消息先编码为字节流(采用 UTF-8 编码格式),再根据指定的 server_address 将数据报发送给服务器,同时通过 print(f'已向服务器发送消息: {message}') 打印发送提示信息,方便查看发送情况。
  • 接收服务器回复:接着调用 client_socket.recvfrom(1024) 尝试从服务器接收回复的数据报,最多接收 1024 字节的数据,当接收到数据报后(即 data 不为空),通过 response = data.decode('utf-8') 将接收到的字节数据按照 UTF-8 编码格式解码为字符串形式,赋值给 response 变量,并通过 print(f'从服务器收到回复: {response}') 打印出服务器回复的内容,实现与服务器之间的简单消息交互。
  • 关闭套接字释放资源:最后调用 client_socket.close() 方法关闭客户端套接字,释放相关资源,确保程序结束时资源被正确回收,避免资源浪费或潜在的资源泄漏问题。

结束语

希望以上对 “套接字是什么?为什么在服务器端与客户端建立了套接字就可以通信了?” 这一问题的全方位解析,包括题目剖析、代码实现与深入的代码分析,能让你顺利敲开网络编程中套接字这扇关键大门。套接字作为网络通信的核心枢纽,无论是基于 TCP 协议构建如网页浏览、文件传输这般稳定可靠的交互场景,还是利用 UDP 协议实现实时性强的游戏、视频流传输等应用,它都展现出无可比拟的灵活性与强大功能,完美架起服务器与客户端之间的信息桥梁。

在后续的编程探索之旅,倘若你立志投身网络应用开发、分布式系统构建等前沿领域,对套接字扎实且深入的理解都将成为你披荆斩棘的有力武器。若在前行路上遭遇网络编程的迷雾,或是渴望拓展更精妙的通信技巧,随时回溯这些知识结晶,我也将一如既往地为你答疑解惑,伴你一路奋进,迈向编程新高峰!

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

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

相关文章

2017年IMO几何预选题第7题

凸四边形 A B C D ABCD ABCD 有内切圆 I I I, △ D A B \triangle DAB △DAB, △ A B C \triangle ABC △ABC, △ B C D \triangle BCD △BCD, △ C D A \triangle CDA △CDA 的内心分别为 I a I_a Ia​, I b I_b Ib​, I c I_c Ic​, I d I_d Id​. △ A I b I d \…

特殊数据类型的深度分析:JSON、数组和 HSTORE 的实用价值

title: 特殊数据类型的深度分析:JSON、数组和 HSTORE 的实用价值 date: 2025/1/4 updated: 2025/1/4 author: cmdragon excerpt: 随着数据管理需求的多样化,许多现代数据库系统开始支持特殊数据类型,以满足更多复杂应用场景的需求。在 PostgreSQL 中,JSON、数组和 HSTOR…

#渗透测试#漏洞挖掘#WAF分类及绕过思路

免责声明 本教程仅为合法的教学目的而准备,严禁用于任何形式的违法犯罪活动及其他商业行为,在使用本教程前,您应确保该行为符合当地的法律法规,继续阅读即表示您需自行承担所有操作的后果,如有异议,请立即停…

【Logstash02】企业级日志分析系统ELK之Logstash 输入 Input 插件

Logstash 使用 Logstash 命令 官方文档 https://www.elastic.co/guide/en/logstash/current/first-event.html #各种插件 https://www.elastic.co/guide/en/logstash/current/input-plugins.html https://www.elastic.co/guide/en/logstash/current/filter-plugins.html htt…

CentOS 7安装Docker详细教程

本文以 CentOS7.8 为例安装 Docker 26.1.4 、Docker Compose、以及 Docker 镜像仓库。 安装方式1:自动安装(使用官方脚本) 使用官网一键安装命令: curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun 或 使用国内 daocloud 一键安…

通过代理用户功能可以实现生产用户的应用滚动修改密码

Oracle通过代理用户功能可以实现生产用户的应用滚动修改密码。 测试例子: 生产用户为jyc密码为jyc 现在要求修改jyc的密码为abc,意味着所有应用都得停止同时修改。 此时可以考虑新建代理用户proxy_jyc,密码为jyc1(实际修改建议…

永磁同步电机控制算法--最大转矩电流比控制((升级版)公式法、曲线拟合法、查表法)

一、原理介绍 id0控制方法在电机输出相同的电磁转矩下电机的定子电流并不是最小的,因此,采用最大转矩电流比控制方法,使得电机在输出相同的电磁转矩下电机定子电流最少,实现该系统的原理框图如图所示。 最大转矩电流比控制也称单位电流输出最大转矩的控制,即控制id以追求最大转…

数据挖掘——决策树分类

数据挖掘——决策树分类 决策树分类Hunt算法信息增益增益比率基尼指数连续数据总结 决策树分类 树状结构,可以很好的对数据进行分类; 决策树的根节点到叶节点的每一条路径构建一条规则;具有互斥且完备的特点,即每一个样本均被且…

小红书怎么看ip所属地?小红书ip属地为什么可以变

小红书,作为当下热门的社交电商平台,不仅为用户提供了丰富的购物与分享体验,还通过展示用户IP属地信息,增强了网络社交的透明度和真实性。然而,不少用户发现,小红书上的IP属地并非一成不变,这引…

springboot使用hutool captcha +vue实现图形验证码

一、效果 使用hutool captcha实现简单的图形验证码&#xff0c;可以参考官网概述 | Hutool 二、实现步骤 1、导入依赖 <!--hutool包--> <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.…

vue3+Echarts+ts实现甘特图

项目场景&#xff1a; vue3Echartsts实现甘特图;发布任务 代码实现 封装ganttEcharts.vue <template><!-- Echarts 甘特图 --><div ref"progressChart" class"w100 h100"></div> </template> <script lang"ts&qu…

EdgeX规则引擎eKuiper

EdgeX 规则引擎eKuiper 一、架构设计 LF Edge eKuiper 是物联网数据分析和流式计算引擎。它是一个通用的边缘计算服务或中间件,为资源有限的边缘网关或设备而设计。 eKuiper 采用 Go 语言编写,其架构如下图所示: eKuiper 是 Golang 实现的轻量级物联网边缘分析、流式处理开源…

【AIGC-ChatGPT进阶提示词指令】AI美食助手的设计与实现:Lisp风格系统提示词分析

引言 在人工智能助手的应用领域中&#xff0c;美食烹饪是一个既专业又贴近生活的方向。本文将详细分析一个基于Lisp风格编写的美食助手系统提示词&#xff0c;探讨其结构设计、功能实现以及实际应用效果。 提出你的菜系&#xff0c;为你分析&#xff0c;并生成图片卡片 提示词…

【从零开始入门unity游戏开发之——C#篇42】C#补充知识——随机数(Random)、多种方法实现string字符串拼接、语句的简写

文章目录 一、随机数1、Random.Next()生成随机整数示例&#xff1a;生成一个随机整数生成指定范围内的随机整数 2、Random.NextSingle生成随机浮点数示例&#xff1a;生成随机浮点数 3、 生成随机字母或字符示例&#xff1a;生成随机字母示例&#xff1a;生成随机小写字母 二、…

吐卡机开发——指令合集—未来之窗行业应用跨平台架构

序号指令10A 09 02 01 01 0D DE20A 09 02 02 01 FD DE30A 09 02 03 01 6D DF40A 09 02 04 01 5D DD50A 09 02 05 01 CD DC60A 09 02 06 01 3D DC70A 09 02 07 01 AD DD80A 09 02 08 01 5D D890A 09 02 09 01 CD D9100A 09 02 10 01 5D D2110A 09 02 11 01 CD D3120A 09 02 12 0…

fpga系列 HDL:verilog 常见错误与注意事项 位宽不匹配+case 语句中没有覆盖所有情况

位宽不匹配问题 信号或操作数的位宽不匹配&#xff0c;可能导致仿真或综合错误。 module top (input wire [3:0] a,output wire [7:0] b );assign b a; endmodulecase 语句中没有覆盖所有情况 module top (input wire [1:0] sel,input wire [7:0] a,input wire [7:0] b,in…

Linux中操作中的无痕命令history技巧

当我们需要查看Linux下的操作记录时&#xff0c;就可以用history命令来查看历史记录 1、关闭history记录功能&#xff0c;如果不想让别人看到自己在Linux上的操作命令&#xff0c;可以用这个命令 set o history 2、打开history记录功能 set -o history3、清空记录 histor…

计算机网络练习题

学习这么多啦&#xff0c;那就简单写几个选择题巩固一下吧&#xff01; 1. 在IPv4分组各字段中&#xff0c;以下最适合携带隐藏信息的是&#xff08;D&#xff09; A、源IP地址 B、版本 C、TTL D、标识 2. OSI 参考模型中&#xff0c;数据链路层的主要功能是&#xff08;…

优化租赁小程序提升服务效率与用户体验的策略与实践

内容概要 在这个快速发展的商业环境中&#xff0c;租赁小程序成为了提升服务效率和用户体验的重要工具。通过对用户需求的深入挖掘&#xff0c;我们发现他们对于功能的便捷性、响应速度和界面的友好性有着极高的期待。因此&#xff0c;针对这些需求&#xff0c;完善租赁小程序…

BP神经网络的反向传播算法

BP神经网络&#xff08;Backpropagation Neural Network&#xff09;是一种常用的多层前馈神经网络&#xff0c;通过反向传播算法进行训练。反向传播算法的核心思想是通过计算损失函数对每个权重的偏导数&#xff0c;从而调整权重&#xff0c;使得网络的预测输出与真实输出之间…