🌀 鱼油のB10g

✦ 不定期更新技术随想

✦ 分享奇妙发现

📌 近期动态:

探索AI和工具使用...

拼客学院 拼客全栈攻防 第8章 第1课——功能速记
今天咱们要搞点刺激的!💻 是不是有时候觉得系统自带的时间不够“个性”,或者想和朋友悄悄分享一张图片?别担心,今天我就带大家用 Python 的 socket 和 datetime 模块,手把手搭建一个超级简单的服务器,不仅能传输当前时间,还能发送图片,让你瞬间变身网络小达人!


准备好了吗?我们开始吧!

首先,咱们得明确一下今天的目标:

  • 一台“被攻击机”(服务器):它会乖乖地监听着,等待“攻击机”的连接,然后把自己的时间和图片传过去。
  • 一台“攻击机”(客户端):它会主动连接服务器,接收时间和图片。

为了让大家看得更明白,我会用 IPv4 和 UDP 协议来实现,这种方式简单粗暴,非常适合咱们今天这种小实验。而且,我会让程序在连接成功时,用字符串清晰地告诉你连接到了哪台服务器和端口,是不是很贴心?


第一步:搭建我们的“被攻击机”(服务器端)

服务器端就像一个耐心等待的接收者,它需要做几件事:

  1. 创建一个 UDP Socket:这是我们进行网络通信的工具。
  2. 绑定 IP 地址和端口:告诉操作系统,我们的服务器要监听哪个地址和端口。
  3. 循环接收数据:服务器会一直运行,等待客户端发送数据。
  4. 发送当前时间:一旦接收到数据,就立即把自己的当前时间打包发回去。
  5. 发送图片:再把一张准备好的图片也传给客户端。

废话不多说,直接上代码!记得,你要准备一张图片放在和脚本同级目录下,比如我这里用的是 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 的结束标记,这样客户端就知道图片什么时候发完了。

第二步:打造我们的“攻击机”(客户端)

客户端相对简单一些,它需要做:

  1. 创建一个 UDP Socket:同样是我们的通信工具。
  2. 发送一个“信号”给服务器:告诉服务器我们来了,请开始你的表演。
  3. 接收时间数据:接收服务器发来的时间信息。
  4. 接收图片数据:接收服务器发送的图片数据,并保存下来。

客户端代码奉上!

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 标记,然后将所有接收到的数据写入文件。

实战演练:怎么运行呢?

  1. 准备工作

    • 确保你的电脑上安装了 Python。
    • 在服务器端脚本所在的文件夹里,放一张名为 test.jpg 的图片(或者修改服务器代码中的 IMAGE_PATH 到你自己的图片路径)。
  2. 先启动服务器端

    • 打开一个命令行窗口 (CMD 或 PowerShell)。
    • 进入你存放 server.py 文件的目录。
    • 运行命令:python server.py
    • 你会看到服务器打印出“服务器已启动,正在监听...”之类的字样。
  3. 再启动客户端

    • 打开另一个命令行窗口。
    • 进入你存放 client.py 文件的目录。
    • 运行命令:python client.py
    • 如果一切顺利,你会看到客户端打印出连接成功、接收时间、接收图片完成的信息,并且在客户端脚本同目录下会生成一个 received_image.jpg 的图片文件。

小小的总结

通过这个小实验,我们是不是对 Python 的 socket 模块有了更直观的认识呢?UDP 协议虽然简单粗暴,但非常适合这种少量数据和快速传输的场景。当然,实际的生产环境中,我们更多会使用 TCP 协议,因为它更可靠,能保证数据完整性和顺序性。

希望这个教程能帮助大家更好地理解网络编程的基础知识!如果你有任何问题,或者想看更多有趣的编程小实验,欢迎在评论区告诉我哦!👍


posted on 2025-06-22 04:27  鱼油YOU  阅读(40)  评论(0)    收藏  举报