Python_socket_udp实现可靠传输

        一般一个典型的物联网系统包括感控层(传感器),网络层和应用层组成,而网络层主要用于实现感控对象与应用层的服务对象之间的通信。本次作业就以TCP/IP 协议栈中传输层协议的应用开发为目标,以UDP方式实现一种感控对象与服务对象之间的通信机制,其体系结构如图1所示。其中感控对象为一个虚拟路灯对象,在实现过程中用随机数模拟其温度、湿度和环境照度等感知数据,灯作为被控对象,可以通过服务器对其进行打开、关闭控制,且用不同颜色表示其开关状态。每个虚拟路灯都将有一个标识,以示区别。而服务对象可以同时与若干个虚拟路灯对象通信,每个虚拟路灯会定期向服务对象发送其当前状态,服务对象可以对任一个虚拟路灯进行开关控制。

PySide2安装:

pip install PySide2

UI:

需添加UIClient.ui和UIServer.ui两个ui组件


 udp客户端:使用时需导入UIClient.ui,并更改代码的文件目录

import random
from socket import *
from PySide2.QtCore import QFile
from PySide2.QtWidgets import QApplication
from PySide2.QtUiTools import QUiLoader
import threading
import time
import datetime
HostIP = gethostbyname(gethostname())
sendAddress = (HostIP, 8081)


class Client:

    def __init__(self):
        # 从文件中加载UI定义
        qfile_Server = QFile("venv/UIClient.ui")
        qfile_Server.open(QFile.ReadOnly)
        qfile_Server.close()
        # 从 UI 定义中动态 创建一个相应的窗口对象
        self.ui = QUiLoader().load(qfile_Server)

        self.wendu = self.shidu = self.zhaodu = 0
        self.ui.btlight.clicked.connect(self.light)
        self.ui.btwork.clicked.connect(self.work)
        self.ui.btstopwork.clicked.connect(self.stopwork)
        self.ui.btsenddata.clicked.connect(self.senddata)
        self.open = False

    # 发送数据,格式:str:data
    def senddata(self):
        dt = datetime.datetime.now()
        self.senddata = '路灯编号:1号\n数据发出时间:'+dt.strftime("%y-%m-%d %H:%M:%S")+'\nTemperature:' + str(self.wendu) + 'degree\nHumidity:' + str(self.shidu) + 'RH\nEnvironmental illumination:' + str(self.zhaodu) + 'lx'
        udpclient.sendto(self.senddata.encode(), sendAddress)

    # 客户端手动开灯
    def light(self):
        if self.open == False:
            self.open = True
            self.ui.btlight.setStyleSheet("background-color:#ffff00;")
        else:
            self.open = False
            self.ui.btlight.setStyleSheet("background-color:#ffffff;")

    # 客户端工作开始
    def work(self):
        self.wendu = round(random.uniform(1, 100), 2)
        self.shidu = round(random.uniform(40, 60), 2)
        self.zhaodu = round(random.uniform(250, 2000), 1)

        self.ui.Textwendu.setText(str(self.wendu) + '摄氏度')
        self.ui.Textshidu.setText(str(self.shidu) + 'RH')
        self.ui.Textzhaodu.setText(str(self.zhaodu) + '勒克斯')
        self.ui.btlight.setEnabled(True)
        self.ui.btstopwork.setEnabled(True)
        self.ui.btwork.setEnabled(False)
        self.ui.Textwendu.setEnabled(True)
        self.ui.Textshidu.setEnabled(True)
        self.ui.Textzhaodu.setEnabled(True)
        self.ui.TextAddress.setEnabled(True)
        self.ui.btsenddata.setEnabled(True)
        self.ui.TextAddress.setText("IP地址:"+HostIP+"端口号:8080")

    # 客户端停止工作
    def stopwork(self):
        self.ui.Textwendu.setText('')
        self.ui.Textshidu.setText('')
        self.ui.Textzhaodu.setText('')
        self.ui.TextAddress.setText('')
        self.ui.btwork.setEnabled(True)
        self.ui.btlight.setEnabled(False)
        self.ui.Textwendu.setEnabled(False)
        self.ui.Textshidu.setEnabled(False)
        self.ui.Textzhaodu.setEnabled(False)
        self.ui.TextAddress.setEnabled(False)
        self.ui.btsenddata.setEnabled(False)
        self.ui.btstopwork.setEnabled(False)
        self.ui.btlight.setStyleSheet("background-color:#d3d3d3")


# 实例化窗口程序
app = QApplication([])
stats = Client()
stats.ui.show()
# 定义socket对象
udpclient = socket(AF_INET, SOCK_DGRAM)
udpclient.bind((HostIP, 8080))
print(f'客户端1启动成功...')


# 接受服务端数据包,并发送握手数据包,格式为str:ACK,data
def receive():
    while (True):
        receiveData = udpclient.recvfrom(10240)
        if stats.ui.btlight.isEnabled():
            if int(receiveData[0].decode()) == 1:
                dt = datetime.datetime.now()
                stats.ui.btlight.setStyleSheet("background-color:#ffff00;")
                udpclient.sendto(("ACK,"+'路灯编号:1号\n数据发出时间:'+dt.strftime("%y-%m-%d %H:%M:%S")+'\nTemperature:' + str(stats.wendu) + 'degree\nHumidity:' + str(stats.shidu) + 'RH\nEnvironmental illumination:illumination:' + str(stats.zhaodu) + 'lx').encode(), sendAddress)
            else:
                dt = datetime.datetime.now()
                stats.ui.btlight.setStyleSheet("background-color:#ffffff;")
                udpclient.sendto(("ACK,"+'路灯编号:1号\n数据发出时间:'+dt.strftime("%y-%m-%d %H:%M:%S")+'\nTemperature:' + str(stats.wendu) + 'degree\nHumidity:' + str(stats.shidu) + 'RH\nEnvironmental illumination:illumination:' + str(stats.zhaodu) + 'lx').encode(), sendAddress)
            time.sleep(0.1)


# 每隔1min发送1次数据(温度,湿度,照度),格式:str:data
def send():
    while(True):
        time.sleep(60)
        dt = datetime.datetime.now()
        udpclient.sendto(('路灯编号:1号\n数据发出时间:'+dt.strftime("%y-%m-%d %H:%M:%S")+'\nTemperature:' + str(stats.wendu) + 'degree\nHumidity:' + str(stats.shidu) + 'RH\nEnvironmental illumination:illumination:' + str(stats.zhaodu) + 'lx').encode(), sendAddress)


# 设置接受数据守护线程
receivethread = threading.Thread(target=receive)
receivethread.setDaemon(True)
receivethread.start()
# 设置发送数据守护线程
sendthread = threading.Thread(target=send)
sendthread.setDaemon(True)
sendthread.start()
# 循环执行
app.exec_()

udp服务端:使用时需导入UIServer.ui,并更改代码的文件目录

from socket import *
from PySide2.QtCore import QFile
from PySide2.QtWidgets import QApplication
from PySide2.QtUiTools import QUiLoader
import threading
import time
import datetime
HostIP=gethostbyname(gethostname())
sendAddress=[(HostIP, 8080),(HostIP, 8082),(HostIP, 8083)]


# 接收客户端的数据包
def receive():
    while(True):
        receiveData = udpserver.recvfrom(102400)
        time.sleep(0.1)
        if stats.ui.btnoserver.isEnabled():
            if receiveData[0].decode().startswith('ACK'):
                dt = datetime.datetime.now()
                data=receiveData[0].decode().split(',')
                stats.ui.Textshangchuan.append('接收时间:'+dt.strftime("%y-%m-%d %H:%M:%S")+'\t'+data[0]+"\nIP地址:"+str(receiveData[1][0])+"\t端口号:"+str(receiveData[1][1])+"\nSuccess!")
                stats.ui.Textshangchuan.ensureCursorVisible()
                stats.ui.Textzhongduan.append('接收时间:'+dt.strftime("%y-%m-%d %H:%M:%S")+'\t'+'IP地址:' + str(receiveData[1][0]))
                stats.ui.Textzhongduan.insertPlainText('\t端口号:' + str(receiveData[1][1]))
                stats.ui.Textzhongduan.append(data[1])
                stats.ui.Textzhongduan.insertPlainText('\n')
                stats.ui.Textzhongduan.ensureCursorVisible()
            else:
                dt = datetime.datetime.now()
                stats.ui.Textzhongduan.append('接收时间:'+dt.strftime("%y-%m-%d %H:%M:%S")+'\t'+'IP地址:'+str(receiveData[1][0]))
                stats.ui.Textzhongduan.insertPlainText('端口号:'+str(receiveData[1][1]))
                stats.ui.Textzhongduan.append(str(receiveData[0].decode()))
                stats.ui.Textzhongduan.insertPlainText('\n')
                stats.ui.Textzhongduan.ensureCursorVisible()


class Server:

    def __init__(self):
        # 从文件中加载UI定义
        qfile_Server = QFile("C:/Users/hp/Desktop/Python/venv/UIServer.ui")
        qfile_Server.open(QFile.ReadOnly)
        qfile_Server.close()
        # 从 UI 定义中动态 创建一个相应的窗口对象
        self.ui = QUiLoader().load(qfile_Server)

        self.ui.btopen.clicked.connect(self.openlight)
        self.ui.btclose.clicked.connect(self.closelight)
        self.ui.btserver.clicked.connect(self.startserver)
        self.ui.btnoserver.clicked.connect(self.stopserver)
        self.ui.btclear.clicked.connect(self.clear)

    # 清空列表
    def clear(self):
        self.ui.Textzhongduan.setText('')
        self.ui.Textshangchuan.setText('')
        self.ui.Textxiafa.setText('')

    # 开灯,发送开灯数据包,格式为:str(1)
    def openlight(self):
        choose = self.ui.comboBox.currentText()
        if choose == '全部':
            for add in sendAddress:
                udpserver.sendto('1'.encode(), add)
                self.ui.Textxiafa.append('开灯指令已发出.'+'\nIP地址:'+add[0]+'端口号:'+str(add[1]))
                self.ui.Textxiafa.ensureCursorVisible()
        elif choose == '路灯1':
            udpserver.sendto('1'.encode(), sendAddress[0])
            self.ui.Textxiafa.append('开灯指令已发出.' + '\nIP地址:' + sendAddress[0][0] + '端口号:' + str(sendAddress[0][1]))
            self.ui.Textxiafa.ensureCursorVisible()
        elif choose == '路灯2':
            udpserver.sendto('1'.encode(), sendAddress[1])
            self.ui.Textxiafa.append('开灯指令已发出.' + '\nIP地址:' + sendAddress[1][0] + '端口号:' + str(sendAddress[1][1]))
            self.ui.Textxiafa.ensureCursorVisible()
        elif choose == '路灯3':
            udpserver.sendto('1'.encode(), sendAddress[2])
            self.ui.Textxiafa.append('开灯指令已发出.' + '\nIP地址:' + sendAddress[2][0] + '端口号:' + str(sendAddress[2][1]))
            self.ui.Textxiafa.ensureCursorVisible()

    # 关灯,发送关灯数据包,格式为:str(0)
    def closelight(self):
        choose = self.ui.comboBox.currentText()
        if choose == '全部':
            for add in sendAddress:
                udpserver.sendto('0'.encode(), add)
                self.ui.Textxiafa.append('关灯指令已发出.' + '\nIP地址:' + add[0] + '端口号:' + str(add[1]))
                self.ui.Textxiafa.ensureCursorVisible()
        elif choose == '路灯1':
            udpserver.sendto('0'.encode(), sendAddress[0])
            self.ui.Textxiafa.append('关灯指令已发出.' + '\nIP地址:' + sendAddress[0][0] + '端口号:' + str(sendAddress[0][1]))
            self.ui.Textxiafa.ensureCursorVisible()
        elif choose == '路灯2':
            udpserver.sendto('0'.encode(), sendAddress[1])
            self.ui.Textxiafa.append('关灯指令已发出.' + '\nIP地址:' + sendAddress[1][0] + '端口号:' + str(sendAddress[1][1]))
            self.ui.Textxiafa.ensureCursorVisible()
        elif choose == '路灯3':
            udpserver.sendto('0'.encode(), sendAddress[2])
            self.ui.Textxiafa.append('关灯指令已发出.' + '\nIP地址:' + sendAddress[2][0] + '端口号:' + str(sendAddress[2][1]))
            self.ui.Textxiafa.ensureCursorVisible()

    # 开始服务/开机
    def startserver(self):
        self.ui.btopen.setEnabled(True)
        self.ui.btclose.setEnabled(True)
        self.ui.btnoserver.setEnabled(True)
        self.ui.Textzhongduan.setEnabled(True)
        self.ui.Textshangchuan.setEnabled(True)
        self.ui.Textxiafa.setEnabled(True)
        self.ui.btserver.setEnabled(False)
        self.ui.btclear.setEnabled(True)
        self.ui.comboBox.setEnabled(True)

    # 停止服务/关机
    def stopserver(self):
        self.ui.Textzhongduan.setText('')
        self.ui.Textshangchuan.setText('')
        self.ui.Textxiafa.setText('')
        self.ui.btserver.setEnabled(True)
        self.ui.btopen.setEnabled(False)
        self.ui.btclose.setEnabled(False)
        self.ui.btnoserver.setEnabled(False)
        self.ui.Textzhongduan.setEnabled(False)
        self.ui.Textshangchuan.setEnabled(False)
        self.ui.Textxiafa.setEnabled(False)
        self.ui.btclear.setEnabled(False)
        self.ui.comboBox.setEnabled(False)


# 实例化窗口程序
app = QApplication([])
stats = Server()
stats.ui.show()
# 定义socket对象
udpserver = socket(AF_INET, SOCK_DGRAM)
udpserver.bind((HostIP,8081))
print(f'服务端启动成功...')
# 设置接受数据守护线程
receivethread = threading.Thread(target=receive)
receivethread.setDaemon(True)
receivethread.start()
# 循环执行
app.exec_()

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

I_love_hanser_QAQ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值