拼客学院 拼客全栈攻防 第8章 第1课——功能速记
今天咱们要搞点刺激的!💻 是不是有时候觉得系统自带的时间不够“个性”,或者想和朋友悄悄分享一张图片?别担心,今天我就带大家用 Python 的 socket 和 datetime 模块,手把手搭建一个超级简单的服务器,不仅能传输当前时间,还能发送图片,让你瞬间变身网络小达人!
准备好了吗?我们开始吧!
首先,咱们得明确一下今天的目标:
- 一台“被攻击机”(服务器):它会乖乖地监听着,等待“攻击机”的连接,然后把自己的时间和图片传过去。
- 一台“攻击机”(客户端):它会主动连接服务器,接收时间和图片。
为了让大家看得更明白,我会用 IPv4 和 UDP 协议来实现,这种方式简单粗暴,非常适合咱们今天这种小实验。而且,我会让程序在连接成功时,用字符串清晰地告诉你连接到了哪台服务器和端口,是不是很贴心?
第一步:搭建我们的“被攻击机”(服务器端)
服务器端就像一个耐心等待的接收者,它需要做几件事:
- 创建一个 UDP Socket:这是我们进行网络通信的工具。
- 绑定 IP 地址和端口:告诉操作系统,我们的服务器要监听哪个地址和端口。
- 循环接收数据:服务器会一直运行,等待客户端发送数据。
- 发送当前时间:一旦接收到数据,就立即把自己的当前时间打包发回去。
- 发送图片:再把一张准备好的图片也传给客户端。
废话不多说,直接上代码!记得,你要准备一张图片放在和脚本同级目录下,比如我这里用的是 test.jpg。
import socket
import datetime
import os
import time
# 服务器配置
SERVER_IP = '0.0.0.0' # 监听所有可用的IP地址
SERVER_PORT = 12345 # 你可以选择一个不常用的端口
# 图片路径
IMAGE_PATH = 'test.jpg' # 替换成你的图片路径
def run_server():
# 1. 创建 UDP Socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 2. 绑定 IP 地址和端口
server_socket.bind((SERVER_IP, SERVER_PORT))
print(f"服务器已启动,正在监听 {SERVER_IP}:{SERVER_PORT}")
print("等待客户端连接...")
while True:
try:
# 3. 接收数据 (UDP 是无连接的,这里只是接收客户端的第一个数据包以获取其地址)
data, client_address = server_socket.recvfrom(1024) # 接收1024字节的数据
print(f"---")
print(f"成功连接到客户端: {client_address[0]}:{client_address[1]}")
# 4. 发送当前时间
current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
time_message = f"当前服务器时间是: {current_time}".encode('utf-8')
server_socket.sendto(time_message, client_address)
print(f"已发送当前时间: {current_time}")
# 5. 发送图片
if os.path.exists(IMAGE_PATH):
with open(IMAGE_PATH, 'rb') as f:
# 分块发送图片,避免一次性发送过大数据包
while True:
image_chunk = f.read(4096) # 每次读取4KB
if not image_chunk:
break
server_socket.sendto(image_chunk, client_address)
time.sleep(0.001) # 短暂休眠,避免发送过快导致丢包
# 发送一个结束标记,告诉客户端图片发送完毕
server_socket.sendto(b'IMAGE_TRANSFER_COMPLETE', client_address)
print(f"图片 '{IMAGE_PATH}' 已发送完成!")
else:
error_message = f"错误:图片文件 '{IMAGE_PATH}' 不存在!".encode('utf-8')
server_socket.sendto(error_message, client_address)
print(f"错误:图片文件 '{IMAGE_PATH}' 不存在!")
print(f"---")
except Exception as e:
print(f"服务器发生错误: {e}")
break # 出现错误就退出循环,可以根据实际情况进行错误处理
server_socket.close()
print("服务器已关闭。")
if __name__ == "__main__":
run_server()
代码解释:
socket.socket(socket.AF_INET, socket.SOCK_DGRAM):这里AF_INET表示使用 IPv4 地址,SOCK_DGRAM表示使用 UDP 协议。server_socket.bind((SERVER_IP, SERVER_PORT)):将服务器绑定到特定的 IP 地址和端口。'0.0.0.0'表示服务器将监听所有可用的网络接口。server_socket.recvfrom(1024):这是 UDP 接收数据的方式,它会返回接收到的数据以及发送方的地址。strftime("%Y-%m-%d %H:%M:%S"):将datetime对象格式化成我们熟悉的时间字符串。- 图片传输小技巧:我们采用分块发送的方式,每次发送一小部分,并添加了一个
IMAGE_TRANSFER_COMPLETE的结束标记,这样客户端就知道图片什么时候发完了。
第二步:打造我们的“攻击机”(客户端)
客户端相对简单一些,它需要做:
- 创建一个 UDP Socket:同样是我们的通信工具。
- 发送一个“信号”给服务器:告诉服务器我们来了,请开始你的表演。
- 接收时间数据:接收服务器发来的时间信息。
- 接收图片数据:接收服务器发送的图片数据,并保存下来。
客户端代码奉上!
import socket
import os
import time
# 服务器配置 (要和服务器端的IP和端口一致哦!)
SERVER_IP = '127.0.0.1' # 如果服务器和客户端在同一台机器上,用127.0.0.1
SERVER_PORT = 12345
# 接收图片保存的路径
RECEIVED_IMAGE_PATH = 'received_image.jpg'
def run_client():
# 1. 创建 UDP Socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
# 2. 发送一个“信号”给服务器
# UDP 是无连接的,这里发送一个空字节,只是为了让服务器知道客户端的地址
client_socket.sendto(b'', (SERVER_IP, SERVER_PORT))
print(f"尝试连接到服务器: {SERVER_IP}:{SERVER_PORT}")
# 3. 接收时间数据
# 设置一个超时时间,避免无限等待
client_socket.settimeout(5) # 5秒超时
time_data, server_address = client_socket.recvfrom(1024)
print(f"成功连接到服务器: {server_address[0]}:{server_address[1]}")
print(f"收到服务器时间: {time_data.decode('utf-8')}")
# 4. 接收图片数据
print("开始接收图片...")
with open(RECEIVED_IMAGE_PATH, 'wb') as f:
while True:
try:
image_chunk, _ = client_socket.recvfrom(4096)
if image_chunk == b'IMAGE_TRANSFER_COMPLETE':
print("图片接收完成!")
break
f.write(image_chunk)
except socket.timeout:
print("接收图片超时,可能图片传输已完成或发生错误。")
break
except Exception as e:
print(f"接收图片时发生错误: {e}")
break
print(f"图片已保存到: {os.path.abspath(RECEIVED_IMAGE_PATH)}")
except socket.timeout:
print(f"连接服务器 {SERVER_IP}:{SERVER_PORT} 超时!请检查服务器是否已启动或IP/端口是否正确。")
except ConnectionRefusedError:
print(f"连接被拒绝!请检查服务器是否已启动或防火墙设置。")
except Exception as e:
print(f"客户端发生错误: {e}")
finally:
client_socket.close()
print("客户端已关闭。")
if __name__ == "__main__":
run_client()
代码解释:
client_socket.sendto(b'', (SERVER_IP, SERVER_PORT)):UDP 是无连接的,这里发送一个空的字节流只是为了让服务器端知道客户端的地址。client_socket.settimeout(5):给recvfrom设置一个超时时间,避免程序卡死。- 图片接收逻辑:客户端会持续接收数据,直到收到
IMAGE_TRANSFER_COMPLETE标记,然后将所有接收到的数据写入文件。
实战演练:怎么运行呢?
-
准备工作:
- 确保你的电脑上安装了 Python。
- 在服务器端脚本所在的文件夹里,放一张名为
test.jpg的图片(或者修改服务器代码中的IMAGE_PATH到你自己的图片路径)。
-
先启动服务器端:
- 打开一个命令行窗口 (CMD 或 PowerShell)。
- 进入你存放
server.py文件的目录。 - 运行命令:
python server.py - 你会看到服务器打印出“服务器已启动,正在监听...”之类的字样。
-
再启动客户端:
- 打开另一个命令行窗口。
- 进入你存放
client.py文件的目录。 - 运行命令:
python client.py - 如果一切顺利,你会看到客户端打印出连接成功、接收时间、接收图片完成的信息,并且在客户端脚本同目录下会生成一个
received_image.jpg的图片文件。
小小的总结
通过这个小实验,我们是不是对 Python 的 socket 模块有了更直观的认识呢?UDP 协议虽然简单粗暴,但非常适合这种少量数据和快速传输的场景。当然,实际的生产环境中,我们更多会使用 TCP 协议,因为它更可靠,能保证数据完整性和顺序性。
希望这个教程能帮助大家更好地理解网络编程的基础知识!如果你有任何问题,或者想看更多有趣的编程小实验,欢迎在评论区告诉我哦!👍
感谢浏览和学习,作者:鱼油YOU,转载请注明原文链接:https://www.cnblogs.com/OmegaYOU3/p/18941112,或者可以➕主播WX:OmegaAnimeman_desu;QQ:3819054512
浙公网安备 33010602011771号