一个典型物联网系统中传输机制的设计与实现
本文书写原由:由于本人习惯保存开发时的所有相关内容所以在上传至GitHub上时连同同学的视频一起上传,在上一篇文章中被指责抄袭,本人心中过意不去便重新又使用了几种方法完成该题目以证清白,希望某些人戾气不要那么重。
(1)题目背景
一般一个典型的物联网系统包括感控层(传感器),网络层和应用层组成,而网络层主 要用于实现感控对象与应用层的服务对象之间的通信。本次作业就以 TCP/IP 协议栈中传输 层协议的应用开发为目标,以 UDP 方式实现一种感控对象与服务对象之间的通信机制,其 体系结构如图 1 所示。其中感控对象为一个虚拟路灯对象,在实现过程中用随机数模拟其温 度、湿度和环境照度等感知数据,灯作为被控对象,可以通过服务器对其进行打开、关闭控 制,且用不同颜色表示其开关状态。每个虚拟路灯都将有一个标识,以示区别。而服务对象 可以同时与若干个虚拟路灯对象通信,每个虚拟路灯会定期向服务对象发送其当前状态,服 务对象可以对任一个虚拟路灯进行开关控制。
(2)题目要求
(1)虚拟路灯状态上传数据直接基于 UDP 实现传输,不考了可靠性,而服务对象发送 给各虚拟路灯的开关命令要利用握手机制实现可靠传输。
(2)基于 UDP 自定义上传、下发数据包格式和传输方式。并实现通信协议的定义、封装和解析。
(3)不限定编程语言。
(3)使用工具
Pycharm、Python、socket、PyQt5
(4)设计思路
客户端
使用Python中PyQt完成页面设计,不同于前文,此处我们设计完全自动化,在前一代码中我们客户端需要手动输入环境状态,在此代码下我们可以使用一个自定义的方法完成生成,并定时发送给服务端。
服务端
服务端依旧使用Qt完成页面设计,此处与前文不同的点是我们也可以根据从服务端收到的信息实时监控展示。
(5)源码
ClientThread.py
import random
import time
import socket
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import *
LocalHost = "127.0.0.1"
def randomMes(): # 随机生成环境状态信息
tep = str(random.randint(-20, 40))
light = str(random.randint(0, 101))
wet = str(random.randint(0, 101))
return tep, light, wet
class Client(QtCore.QThread):
client_socket = None
_signal_data = pyqtSignal(tuple)
_signal_result = pyqtSignal(str)
def __init__(self):
super(Client, self).__init__()
self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
def __del__(self):
self.wait()
def run(self):
while True:
data = randomMes()
self._signal_data.emit(data)
data_t = data[0]
data_l = data[1]
data_w = data[2]
self.client_socket.sendto(data_t.encode("utf8"), (LocalHost, 8000))
self.client_socket.sendto(data_w.encode("utf8"), (LocalHost, 8000))
self.client_socket.sendto(data_l.encode("utf8"), (LocalHost, 8000))
self.status, self.address = self.client_socket.recvfrom(1024)
if self.status == b'open':
self._signal_result.emit("Open")
else:
self._signal_result.emit("Close")
time.sleep(5)
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.setWindowModality(QtCore.Qt.ApplicationModal)
MainWindow.resize(457, 304)
self.labelstatus = QtWidgets.QLabel(MainWindow)
self.labelstatus.setGeometry(QtCore.QRect(20, 40, 111, 51))
self.labelstatus.setTextFormat(QtCore.Qt.PlainText)
self.labelstatus.setScaledContents(False)
self.labelstatus.setAlignment(QtCore.Qt.AlignCenter)
self.labelstatus.setWordWrap(False)
self.labelstatus.setObjectName("labelstatus")
self.labelStatus = QtWidgets.QLabel(MainWindow)
self.labelStatus.setGeometry(QtCore.QRect(160, 50, 101, 31))
self.labelStatus.setText("")
self.labelStatus.setAlignment(QtCore.Qt.AlignCenter)
self.labelStatus.setObjectName("labelStatus")
self.labelStatus2 = QtWidgets.QLabel(MainWindow)
self.labelStatus2.setGeometry(QtCore.QRect(30, 80, 101, 61))
self.labelStatus2.setTextFormat(QtCore.Qt.AutoText)
self.labelStatus2.setAlignment(QtCore.Qt.AlignCenter)
self.labelStatus2.setObjectName("labelStatus2")
self.labelTem = QtWidgets.QLabel(MainWindow)
self.labelTem.setGeometry(QtCore.QRect(90, 150, 72, 15))
self.labelTem.setObjectName("labelTem")
self.labelWet = QtWidgets.QLabel(MainWindow)
self.labelWet.setGeometry(QtCore.QRect(90, 190, 72, 15))
self.labelWet.setObjectName("labelWet")
self.labelLight = QtWidgets.QLabel(MainWindow)
self.labelLight.setGeometry(QtCore.QRect(90, 230, 72, 15))
self.labelLight.setObjectName("labelLight")
self.pushButton = QtWidgets.QPushButton(MainWindow)
self.pushButton.setGeometry(QtCore.QRect(300, 120, 111, 71))
self.pushButton.setObjectName("pushButton")
self.label = QtWidgets.QLabel(MainWindow)
self.label.setGeometry(QtCore.QRect(140, 140, 61, 31))
self.label.setObjectName("label")
self.label_2 = QtWidgets.QLabel(MainWindow)
self.label_2.setGeometry(QtCore.QRect(140, 180, 61, 31))
self.label_2.setObjectName("label_2")
self.label_3 = QtWidgets.QLabel(MainWindow)
self.label_3.setGeometry(QtCore.QRect(140, 220, 61, 31))
self.label_3.setObjectName("label_3")
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "Ludeng"))
self.labelstatus.setText(_translate("MainWindow", "路灯状态:"))
self.labelStatus2.setText(_translate("MainWindow", "环境状态:"))
self.labelTem.setText(_translate("MainWindow", "温度:"))
self.labelWet.setText(_translate("MainWindow", "湿度:"))
self.labelLight.setText(_translate("MainWindow", "亮度:"))
self.pushButton.setText(_translate("MainWindow", "开启"))
self.label.setText(_translate("MainWindow", "0"))
self.label_2.setText(_translate("MainWindow", "0%"))
self.label_3.setText(_translate("MainWindow", "0"))
self.socketThread = None
self.pushButton.clicked.connect(self.start_login)
def start_login(self):
if not self.socketThread:
self.socketThread = Client()
self.socketThread._signal_data.connect(self.call_back) # 绑定修改室内状态信息
self.socketThread._signal_result.connect(self.displayresult) # 绑定修改灯状态信息
self.socketThread.start()
def call_back(self, data):
self.label.setText(str(data[0]))
self.label_2.setText(str(data[2]) + "%")
self.label_3.setText(str(data[1]))
def displayresult(self, result):
self.labelStatus.setText(str(result))
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
ServerLight.py
import socket
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import *
class Thread(QThread):
_signal = pyqtSignal(int, str, tuple, str)
ip_address = []
udp_socket = None
def __init__(self):
super(Thread, self).__init__()
print("正在启动服务端")
# 创建套接字
self.udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # udp IPV4 tcp IPV4
# 绑定本地信息
self.udp_socket.bind(('', 8000))
print("启动成功")
def __del__(self):
self.wait()
def run(self):
while True:
# 接收终端的数据
recv_data_T, address = self.udp_socket.recvfrom(1024) # 接收温度
recv_data_W, address = self.udp_socket.recvfrom(1024) # 接收湿度
recv_data_L, address = self.udp_socket.recvfrom(1024) # 接收环境照度
recv_data_T = recv_data_T.decode('utf-8')
recv_data_W = recv_data_W.decode('utf-8')
recv_data_L = recv_data_L.decode('utf-8')
print("您接收到来自" + address[0] + "的数据为")
print("温度为:" + recv_data_T)
print("湿度为:" + recv_data_W + "%")
print("亮度为:" + recv_data_L)
# 退出数据传送判断
if recv_data_T == '#' or recv_data_W == '#' or recv_data_L == '#':
break
# 判断是否满足开灯条件
if recv_data_T <= '15' and recv_data_W <= '50' or recv_data_L <= '30':
self.udp_socket.sendto(b"open", address)
self.bind(address, (recv_data_T, recv_data_W, recv_data_L), 'open')
elif recv_data_T != '20' or recv_data_L != '5' or recv_data_W != '25':
self.udp_socket.sendto(b"close", address)
self.bind(address, (recv_data_T, recv_data_W, recv_data_L), 'close')
def bind(self, address, data, status):
if address[0] in self.ip_address:
self._signal.emit(self.ip_address.index(address[0]), address[0], data, status)
else:
if len(self.ip_address) < 3:
self.ip_address.append(address[0])
self._signal.emit(self.ip_address.index(address[0]), address[0], data, status)
else:
self._signal.emit(-1, (), '')
@property
def signal(self):
return self._signal
class Ui_ServerLight(object):
ip_address = []
thread = None
list1 = []
list2 = []
list3 = []
def setupUi(self, ServerLight):
ServerLight.setObjectName("ServerLight")
ServerLight.setEnabled(True)
ServerLight.resize(640, 480)
ServerLight.setAutoFillBackground(False)
self.centralwidget = QtWidgets.QWidget(ServerLight)
self.centralwidget.setObjectName("centralwidget")
self.light1 = QtWidgets.QFrame(self.centralwidget)
self.light1.setGeometry(QtCore.QRect(30, 19, 201, 211))
self.light1.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.light1.setFrameShadow(QtWidgets.QFrame.Raised)
self.light1.setObjectName("light1")
self.liststatus1 = QtWidgets.QListView(self.light1)
self.liststatus1.setGeometry(QtCore.QRect(10, 60, 171, 131))
self.liststatus1.setObjectName("liststatus1")
self.label = QtWidgets.QLabel(self.light1)
self.label.setGeometry(QtCore.QRect(20, 10, 60, 16))
self.label.setObjectName("label")
self.ip1 = QtWidgets.QLabel(self.light1)
self.ip1.setGeometry(QtCore.QRect(70, 10, 60, 16))
self.ip1.setObjectName("ip1")
self.light3 = QtWidgets.QFrame(self.centralwidget)
self.light3.setGeometry(QtCore.QRect(30, 240, 201, 221))
self.light3.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.light3.setFrameShadow(QtWidgets.QFrame.Raised)
self.light3.setObjectName("light3")
self.ip3 = QtWidgets.QLabel(self.light3)
self.ip3.setGeometry(QtCore.QRect(70, 10, 60, 16))
self.ip3.setObjectName("ip3")
self.label_3 = QtWidgets.QLabel(self.light3)
self.label_3.setGeometry(QtCore.QRect(20, 10, 60, 16))
self.label_3.setObjectName("label_3")
self.liststatus3 = QtWidgets.QListView(self.light3)
self.liststatus3.setGeometry(QtCore.QRect(10, 60, 171, 131))
self.liststatus3.setObjectName("liststatus1_2")
self.light2 = QtWidgets.QFrame(self.centralwidget)
self.light2.setGeometry(QtCore.QRect(309, 19, 201, 211))
self.light2.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.light2.setFrameShadow(QtWidgets.QFrame.Raised)
self.light2.setObjectName("light2")
self.ip2 = QtWidgets.QLabel(self.light2)
self.ip2.setGeometry(QtCore.QRect(70, 10, 60, 16))
self.ip2.setObjectName("ip2")
self.label_2 = QtWidgets.QLabel(self.light2)
self.label_2.setGeometry(QtCore.QRect(20, 10, 60, 16))
self.label_2.setObjectName("label_2")
self.liststatus2 = QtWidgets.QListView(self.light2)
self.liststatus2.setGeometry(QtCore.QRect(10, 60, 171, 131))
self.liststatus2.setObjectName("liststatus2")
self.openServer = QtWidgets.QPushButton(self.centralwidget)
self.openServer.setGeometry(QtCore.QRect(530, 250, 81, 26))
self.openServer.setObjectName("openServer")
self.CloseServer = QtWidgets.QPushButton(self.centralwidget)
self.CloseServer.setGeometry(QtCore.QRect(530, 300, 81, 26))
self.CloseServer.setObjectName("CloseServer")
self.devicemsg = QtWidgets.QFrame(self.centralwidget)
self.devicemsg.setGeometry(QtCore.QRect(309, 240, 201, 211))
self.devicemsg.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.devicemsg.setFrameShadow(QtWidgets.QFrame.Raised)
self.devicemsg.setObjectName("devicemsg")
self.devicelist = QtWidgets.QListView(self.devicemsg)
self.devicelist.setGeometry(QtCore.QRect(0, 50, 201, 161))
self.devicelist.setObjectName("devicelist")
self.label_4 = QtWidgets.QLabel(self.devicemsg)
self.label_4.setGeometry(QtCore.QRect(10, 10, 60, 16))
self.label_4.setObjectName("label_4")
self.label_5 = QtWidgets.QLabel(self.centralwidget)
self.label_5.setGeometry(QtCore.QRect(519, 25, 101, 41))
self.label_5.setObjectName("label_5")
self.serverstatus = QtWidgets.QLabel(self.centralwidget)
self.serverstatus.setGeometry(QtCore.QRect(550, 70, 31, 21))
self.serverstatus.setObjectName("serverstatus")
ServerLight.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(ServerLight)
self.statusbar.setObjectName("statusbar")
ServerLight.setStatusBar(self.statusbar)
self.retranslateUi(ServerLight)
QtCore.QMetaObject.connectSlotsByName(ServerLight)
def retranslateUi(self, ServerLight):
_translate = QtCore.QCoreApplication.translate
ServerLight.setWindowTitle(_translate("ServerLight", "ServerLight"))
self.label.setText(_translate("ServerLight", "设备1"))
self.ip1.setText(_translate("ServerLight", "ip地址1"))
self.ip3.setText(_translate("ServerLight", "ip地址3"))
self.label_3.setText(_translate("ServerLight", "设备3"))
self.ip2.setText(_translate("ServerLight", "ip地址2"))
self.label_2.setText(_translate("ServerLight", "设备2"))
self.openServer.setText(_translate("ServerLight", "开机"))
self.CloseServer.setText(_translate("ServerLight", "关机"))
self.label_4.setText(_translate("ServerLight", "设备信息"))
self.label_5.setText(_translate("ServerLight", "当前服务器状态:"))
self.serverstatus.setText(_translate("ServerLight", "关机"))
# 开关事件
self.openServer.clicked.connect(self.server)
self.CloseServer.clicked.connect(self.server)
# 开关服务器
def server(self):
if self.serverstatus.text() == "关机" and not self.thread:
self.thread = Thread()
self.thread.start()
self.serverstatus.setText("开机")
self.thread.signal.connect(self.display)
elif self.serverstatus.text() == "开机" and self.thread:
self.thread = None
self.serverstatus.setText("关机")
def display(self, event, ip, msg, status):
if ip and ip not in self.ip_address:
self.ip_address.append(ip)
slm = QStringListModel()
slm.setStringList(self.ip_address)
self.devicelist.setModel(slm)
if event == 0:
self.ip1.setText(ip)
self.list1.append("温度:"+msg[0]+",湿度:"+msg[1]+"%,亮度:"+msg[2])
slm = QStringListModel()
slm.setStringList(self.list1)
self.liststatus1.setModel(slm)
elif event == 1:
self.ip2.setText(ip)
elif event == 2:
self.ip3.setText(ip)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
ServerLight = QtWidgets.QMainWindow()
ui = Ui_ServerLight()
ui.setupUi(ServerLight)
ServerLight.show()
sys.exit(app.exec_())