python实现socket通信

引言

        最近工作需要实现将树莓派处理的信号文件与工控机进行通信,然后将文件传输到工控机,并且传输完一个就删除一个。所以想着利用socket通信初步模拟出来一个流程,等待之后再将它部署到具体的树莓派和工控机下。主要利用的是python的socket库,主要是将树莓派作为服务器端,工控机作为客户端,树莓派一旦监测到指定文件夹下有文件产生就进行通信传输。

实现

1.服务器端:(第一种监听方式)

(1)主要是进行连接询问建立后,通过python的watchdog库实时监控指定文件夹是否有“文件生成”的事件发生,一旦有,就进行send_file。并且为了防止文件正在生成而被发送,采用的是利用0.2秒来检查是否有文件大小变化的情况。

(2)每个文件结束后都标注了“b'END_OF_FILE_MARKER\r\n'”,以此来防止提前传入下一个文件的内容。

import socket
import os
import time
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler


WATCHED_FOLDER = 'E:\\network_socket\\test_network'
HOST = 'localhost'
PORT = 8888
CHECK_INTERVAL = 0.2  # 以秒为单位,检查文件大小变化的间隔时间

class FileHandler(FileSystemEventHandler):
    def __init__(self, conn):
        self.conn = conn

    def on_created(self, event):
        if not event.is_directory:
            self.wait_for_file_completion(event.src_path)

    def wait_for_file_completion(self, file_path):
        initial_size = os.path.getsize(file_path)
        time.sleep(CHECK_INTERVAL)  # 等待一段时间,让文件有时间完成生成
        final_size = os.path.getsize(file_path)

        # 检查文件大小是否稳定
        while final_size != initial_size:
            initial_size = final_size
            time.sleep(CHECK_INTERVAL)
            final_size = os.path.getsize(file_path)

        # 文件生成完成后发送文件
        self.send_file(file_path)

    def send_file(self, file_path):
        try:
            file_name = os.path.basename(file_path)
            self.conn.send(file_name.encode())  # 发送文件名
            self.conn.sendall(b'\r\n')

            with open(file_path, 'rb') as f:
                while True:
                    data = f.read(1024)
                    if not data:
                        break
                    self.conn.sendall(data)  # 发送文件内容

            # 发送文件结束标志
            self.conn.sendall(b'END_OF_FILE_MARKER\r\n')

            print(f"File {file_path} has been sent")
            os.remove(file_path)  # 发送完成后删除文件
            print(f"File {file_path} has been deleted")



        except Exception as e:
            print(f"An error occurred while sending the file: {e}")


def server_program():
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.bind((HOST, PORT))
    server_socket.listen(1)

    print("Server listening...")
    conn, addr = server_socket.accept()
    print(f"Connection from {addr} has been established!")

    event_handler = FileHandler(conn)
    observer = Observer()
    observer.schedule(event_handler, path=WATCHED_FOLDER, recursive=False)

    try:
        observer.start()

    except KeyboardInterrupt:
        observer.stop()
    except Exception as e:
        print(f"An error occurred: {e}")
    finally:
        observer.join()
        conn.close()
        server_socket.close()


if __name__ == '__main__':
    server_program()

服务器端:(第二种监听方式)

采用轮询的方式去访问文件,并按照时间戳大小排列进行读取。

import os
import socket
import time

WATCHED_FOLDER = 'E:\\network_socket\\test_network'
HOST = 'localhost'
PORT = 8888
BUFFER_SIZE = 4096
POLL_INTERVAL = 1  # seconds


def get_sorted_files_by_name(folder_path):
    files = [os.path.join(folder_path, f) for f in os.listdir(folder_path) if
             os.path.isfile(os.path.join(folder_path, f))]
    return sorted(files, key=lambda f: os.path.basename(f))


def send_file(client_socket, file_path):
    try:
        file_name = os.path.basename(file_path)
        client_socket.send(file_name.encode())  # 发送文件名
        client_socket.sendall(b'\r\n')

        with open(file_path, 'rb') as f:
            while True:
                data = f.read(1024)
                if not data:
                    break
                client_socket.sendall(data)  # 发送文件内容

        # 发送文件结束标志
        client_socket.sendall(b'END_OF_FILE_MARKER\r\n')

        print(f"File {file_path} has been sent")
        os.remove(file_path)  # 发送完成后删除文件
        print(f"File {file_path} has been deleted")

    except Exception as e:
        print(f"An error occurred while sending the file: {e}")


def handle_client(client_socket):
    try:
        files = get_sorted_files_by_name(WATCHED_FOLDER)
        for file_path in files:
            send_file(client_socket, file_path)
            print(f"Sent file: {file_path}")
        print("All files sent.")
    except Exception as e:
        print(f"An error occurred: {e}")


def monitor_folder():
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.bind((HOST, PORT))
    server_socket.listen(1)

    print("Server listening...")

    conn, addr = server_socket.accept()
    print(f"Connection from {addr} has been established!")

    try:
        while True:
            handle_client(conn)
            time.sleep(POLL_INTERVAL)

    except Exception as e:
        print(f"An error occurred: {e}")
    finally:
        conn.close()
        server_socket.close()


if __name__ == '__main__':
    monitor_folder()

2.客户端:将文件逐个保存到工控机下。其次还有可以直接传字符流,不用再存储文件,相关代码也很好改正,在此不必赘述,根据实际情况选择需求。

import socket

def client_program(client_socket):
    try:
        # 接收文件名
        file_name = client_socket.recv(1024).decode()
        print(file_name)
        if not file_name:
            raise Exception("No file name received111")
        if file_name == 'END_OF_FILE_MARKER':
            raise Exception("No file name received222")

        # 接收文件数据
        file_path = f'E:\\network_socket\\recv_file\\{file_name}'  # 本地保存路径
        with open(file_path, 'wb') as f:
            while True:
                data = client_socket.recv(1024)
                if data.endswith(b'END_OF_FILE_MARKER\r\n'):
                    data = data[:-len(b'END_OF_FILE_MARKER\r\n')]
                    if data:
                        f.write(data)
                    break
                if not data:
                    break
                f.write(data)

        print(f"File received and saved as {file_path}")

    except Exception as e:
        print(f"An error occurred: {e}")



if __name__ == '__main__':
    host = 'localhost'  # 服务器的IP地址
    port = 8888  # 服务器的端口号
    # 创建socket对象
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client_socket.connect((host, port))  # 连接到服务器
    while True:
        client_program(client_socket)


    # client_socket.close()

对此,还在服务器端模拟了文件生成进行验证

import os
import time


def generate_files_in_folder(folder_path, interval=5):
    """
    在指定文件夹中每隔一定时间生成一个文件。

    :param folder_path: 文件夹的路径,用于存放生成的文件。
    :param interval: 生成文件的时间间隔(秒)。
    """
    if not os.path.exists(folder_path):
        print(f"指定的文件夹不存在: {folder_path}")
        return

    while True:
        # 生成一个唯一的文件名(这里使用时间戳和随机数)
        file_name = f"file_{int(time.time())}_{os.urandom(4).hex()}.txt"
        file_path = os.path.join(folder_path, file_name)

        # 创建文件并写入一万个数
        with open(file_path, 'w') as file:
            for i in range(10000):
                file.write(f"{i}\n")
        print(f"已创建文件: {file_path}")

        # 等待指定的时间间隔
        time.sleep(interval)

    # 示例用法


folder_path = "E:\\network_socket\\test_network"  # 请替换为你的文件夹路径
generate_files_in_folder(folder_path, 1)  # 每隔5秒生成一个文件

运行结果

开始:

1.先运行server.py

2.再运行client.py

3.再开始创建文件

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值