代码应用背景为工业机床故障检测,代码分客户端和服务端两部分,两部分可以互相发送数据,客户端可以同时存在多个(使用了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()