python实现TCP/IP多线程通信

本文详细描述了一个基于Python的工业机床故障检测系统,包括客户端使用多线程与服务端进行数据交换,以及服务端的类结构设计,展示了如何通过TCP协议实现实时故障判断和通信管理。
摘要由CSDN通过智能技术生成

代码应用背景为工业机床故障检测,代码分客户端和服务端两部分,两部分可以互相发送数据,客户端可以同时存在多个(使用了python的threading线程),机床数据库应该已经上传在文章里了。哦对了,服务端被我包装成了一个类。代码如下:

客户端

import socket
import time
from threading import Thread

import keyboard as keyboard
import numpy as np
import pandas as pd

# 1.创建socket
tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 2. 链接服务器
hostname = socket.gethostname()
ip = socket.gethostbyname(hostname)
print("本机ip:", ip)
server_addr = (ip, 7788)
tcp_socket.connect(server_addr)
print("成功链接服务端!")
tcp_socket.send("client1".encode("gbk"))  # 发送客户端名称
is_end = False


def recv_message(server_socket, finish_message):
    """
    接收服务端消息,此函数将作为子线程运行
    """
    message = server_socket.recv(1024).decode(encoding='gbk')
    if finish_message == message:
        print("服务端主动中断连接")
        global is_end
        is_end = True


server_thread = Thread(target=recv_message, args=(tcp_socket, "finish"))
server_thread.daemon = True
server_thread.start()

# 3. 发送数据
data = (np.array(pd.read_csv('out_csv.csv').astype('str'))).tolist()
count = 0
while not is_end:
    # send_data = input("请输入要发送的数据:")
    send_data = ','.join(data[count][1:8])
    print("发送数据:", send_data)
    try:
        tcp_socket.send(send_data.encode("gbk"))
    except ConnectionResetError as error:
        print("服务端中断链接!")
        break
    count += 1
    time.sleep(0.5)
    if keyboard.is_pressed('q'):
        tcp_socket.send('finish'.encode("gbk"))
        print("客户端主动退出!")
        break

# 4. 关闭套接字
tcp_socket.close()

服务端

import csv
import socket
import time
from threading import Thread
import joblib
import keyboard


class Server:

    def __init__(self):

        # 本地信息
        hostname = socket.gethostname()
        ip = socket.gethostbyname(hostname)
        print("本机ip:", ip)
        self.address = (ip, 7788)

        # 客户端连接池
        self.client_pool = {}

        # 初始化服务端
        self.socket_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket_server.bind(self.address)
        self.socket_server.listen(5)
        print("服务端初始化完成,等待连接······")

        # 载入故障判断网络和机床错误信息对应标签
        self.tree = joblib.load('tree.pkl')
        self.label = ['工具磨损故障 (TWF)', '散热故障 (HDF)', '电源故障 (PWF)', '过度应变故障 (OSF)', '随机故障 (RNF)']

        # 保存传输的所有数据及判断结果
        file_path = "machine_data.csv"
        self.file = open(file_path, "a+", newline='')
        self.writer = csv.writer(self.file)

        # 保存故障机床数据及判断结果
        error_file_path = "error_data.csv"
        self.error_file = open(error_file_path, "a+", newline='')
        self.error_writer = csv.writer(self.error_file)

        # 服务端结束标志
        self.is_end = False

    def new_client(self):
        """
        持续等待客户端连接
        """
        while True:
            client_socket, clientAddr = self.socket_server.accept()  # 阻塞,等待客户端连接
            if self.is_end:
                break
            # 给每个客户端创建一个独立的线程进行管理
            client_thread = Thread(target=self.recv_message, args=(client_socket, clientAddr))
            # 设置为守护线程,即主程序关闭时线程立即关闭
            client_thread.daemon = True
            client_thread.start()
        print("已关闭客户端连接通道")

    def start(self):
        """
        使服务器开始接收客户端链接的函数
        """
        start_thread = Thread(target=self.new_client)  # 此处new_client函数不能加括号,不然会导致进程自动运行并阻塞主进程
        start_thread.daemon = True  # 此处必须设置进程为守护进程,否则主进程无法停止
        start_thread.start()

    def recv_message(self, client_socket, clientAddr):
        """
        接收客户端消息,此函数将作为子线程运行
        """
        client_name = client_socket.recv(1024).decode(encoding='gbk')  # 接收1024个字节
        self.client_pool[client_name] = client_socket
        print("成功链接客户端!客户端名称:", client_name, ",客户端地址:", clientAddr)

        # 服务器将持续接收消息,直到收到客户端的“finish”信息
        while True:
            try:
                message = client_socket.recv(1024).decode(encoding='gbk')
                if "finish" == message:
                    self.delete_client(client_name)
                    print("客户端主动中断连接,设备名:" + client_name, ",地址:", clientAddr)
                    break
                elif "" == message:
                    print("客户端中断连接成功,设备名:" + client_name, ",地址:", clientAddr)
                    break
                else:
                    self.mess_handling(message, client_name)
            except ConnectionAbortedError as e:  # 关闭服务端时recv函数仍在线程中,将报错
                break
            except Exception as other:
                print("接收消息失败,断开", client_name, "客户端连接")
                print("错误信息为:", other)
                self.delete_client(client_name)

    def mess_handling(self, message, client_name):
        """
        处理传输信息,进行故障判断并保存数据
        """
        print('接收到的数据为:', message)
        message_list = message.split(',')
        recv_productID = message_list[0]
        recv_info = [float(a) for a in message_list[1:7]]
        prediction = self.tree.predict([recv_info])[0]
        if 1 not in prediction:
            pred = "编号" + recv_productID + "设备正常"
        else:
            pred_error = [self.label[i] for i in range(len(prediction)) if prediction[i] != 0]
            pred = "编号" + recv_productID + "设备故障" + ",故障类型为" + ','.join(pred_error)
            self.error_writer.writerow(
                message_list + prediction.tolist() + [client_name] +
                [time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())])
        self.writer.writerow(
            message_list + prediction.tolist() + [client_name] + [time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())])
        print("故障诊断结果:", pred)

    def delete_client(self, client_name):
        """
        删除单个客户端`
        """
        self.client_pool[client_name].send("finish".encode("gbk"))
        del self.client_pool[client_name]

    def delete(self):
        """
        类释放时,自动关闭客户端所有链接并关闭数据文件
        """
        print("开始释放服务器······")
        # 设置程序终止并链接一个空服务器以使new_client线程退出
        self.is_end = True
        tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        tcp_socket.connect(self.address)
        tcp_socket.close()

        # 断开所有客户端链接
        for client_name in list(self.client_pool):
            self.delete_client(client_name)
        time.sleep(1)

        # 关闭数据文件
        self.file.close()
        self.error_file.close()
        print("成功关闭所有文件\n服务器释放完毕!")


server = Server()
server.start()

# 用户按下esc终止服务端
keyboard.wait('esc')
server.delete()


参考文章:
TCP基础
多线程创建
线程防阻塞

  • 8
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值