大家好,
我遇到了一些套接字通信编码的问题。我有两个pi通过TCP / IP与python脚本进行通信。这个想法是一个pi(客户端)读取温度/湿度传感器数据并将其发送到另一个pi(服务器),在那里它将存储在SQLite数据库中。在未来,我希望多个pi(客户端)通过传感器数据发送到一个(Web)服务器和数据库,以便在本地网站上显示数据。
我已经为服务器端和客户端编写了一些python代码,它运行良好。如果我启动服务器端,它将侦听其他连接。当我启动客户端时,它将生成传感器数据并将其发送到服务器。服务器接收数据。但是当我想要接近连接以便为(未来的其他pi)腾出空间时,它会完全终止脚本并且不会收听新的"电话"。请参阅下面的代码双方。代码是用Python2.7编写的。
该项目的目标:在动物园内设置监视器并记录多个展览和水族馆的温度和湿度,在每个展览中显示LCD上的信息,使用LED作为警告,并具有中央 - 用于存储/记录数据的服务器,与中央计算机一起显示。
RaspiServer - 服务器端
import socket
from LED import callLED
host = ''
port = 5560
def setupServer():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print("Socket created.")
try:
s.bind((host, port))
except socket.error as msg:
print(msg)
print("Socket bind complete.")
return s
def setupConnection():
s.listen(1)
conn, address = s.accept()
print("Connected to: " + address[0] + ":" + str(address[1]))
return conn
def dataTransfer(conn):
while True:
data = conn.recv(1024)
data = data.decode('utf-8')
dataMessage = data.split(":", 2)
command = dataMessage[0]
humidity = dataMessage[1]
temperature = dataMessage[2]
if command == 'DATA':
print("Received: " + humidity + " : " + temperature)
callLED()
elif command == 'EXIT':
print("Disconnected with Client")
break
else:
reply = 'Unknow Command'
conn.sendall(str.encode(reply))
Print("Reply has been send.")
conn.close()
s = setupServer()
while True:
try:
conn = setupConnection()
dataTransfer(conn)
except:
break
在客户端有三个python脚本,主要python脚本与其他脚本通信。我决定将它分成多个脚本,也可以单独使用它们(闪烁的LED,LCD上的显示数据等)。
RaspiMonitor - 客户端
Run this script on client-side
from time import sleep
from client_sensordata import GetTemp
from monitor_client import transmit
sleepTime = 20
def tempMonitorServer():
humidity, temperature = GetTemp()
temp = str(temperature)
hum = str(humidity)
message = "DATA:" + hum + ":" + temp
print("Transmitting Data.")
response = transmit(message)
print(response)
while True:
tempMonitorServer()
sleep(sleepTime)
Use this script to send and receive data over TCP/IP
import socket
host = '192.168.2.3'
port = 5560
def setupSocket():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
return s
def sendReceive(s, message):
s.send(str.encode(message))
print("Message transmitted")
reply = s.recv(1024)
print("We have received a reply.")
print("Send closing message.")
s.send(str.encode("EXIT"))
s.close()
reply = reply.decode('utf-8')
return reply
def transmit(message):
s = setupSocket()
response = sendReceive(s, message)
return response
Use this script to retrieve sensor data
def GetReading():
import sys
import Adafruit_DHT
humidity, temperature = Adafruit_DHT.read_retry(Adafruit_DHT.DHT22, 17)
if humidity is not None and temperature is not None:
print('Reading sensor data')
return humidity, temperature
else:
print('no sensor data')
def GetTemp():
humidity, temperature = GetReading()
name = "DHT22Client1"
print('Read sensor: {0} humidity: {1:0.2f}% temperature: {2:0.2f}C'.format(name, humidity, temperature))
return humidity, temperature
终端输出
Terminal output, left server and right the client
有人可以提供一些提示或帮助,或者告诉我为什么要解决这个问题?我已搜索过多个帖子和其他帖子,但无法找到解决方案。
提前感谢您提供的每一项帮助。
答案 0 :(得分:2)
您的服务器套接字设置可能没有错误。服务器套接字的工作方式是应该始终打开侦听新连接。当您接受来自客户端的连接(s.accept)时,它会创建与客户端的连接。如果您关闭该连接,它不应该影响服务器监听incomming套接字,客户端或conn到客户端的数量仅受您在服务器socket.listen(NUMBER)中指定的数量的限制。达到该数量后,将拒绝传入连接。
def setupServer():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print("Socket created.")
try:
s.bind((host, port))
s.listen(5)
except socket.error as msg:
print(msg)
print("Socket bind complete.")
return s
然后从setup connection()
中删除s.listen我还建议您在新线程中处理数据传输(),以便能够连续处理连续的传入连接。
答案 1 :(得分:0)
我建议不要重复关闭和打开新的套接字,而是建议维护多个打开的套接字连接服务器端并使用select()方法处理每个套接字。
答案 2 :(得分:0)
现在适用的代码(仍在构建中,用于添加更多功能)是:
服务器侧强>
import socket
import sys
from LED import callLED
from monitor_log3 import ExtractStoreData
# Create a TCP/IP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Bind the socket to the port
server_address = ('', 5560)
print >>sys.stderr, 'Starting up on %s port %s' % server_address
sock.bind(server_address)
# Listen for incoming connections
sock.listen(1)
while True:
# Wait for a connection
print >>sys.stderr, 'Waiting for a connection'
connection, client_address = sock.accept()
try:
print >>sys.stderr, 'Connection from', client_address
# Receive the data in small chunks and retransmit it
while True:
data = connection.recv(1024)
data = data.decode('utf-8')
message = data
if data:
print >>sys.stderr, 'Send data receive confirmation'
connection.sendall(data)
callLED()
ExtractStoreData(message)
else:
print >>sys.stderr, 'No more data from', client_address
break
finally:
# Clean up the connection
print >>sys.stderr, 'Closing connection'
print >>sys.stderr, '------------------'
connection.close()
客户端看起来像这样:
<强>客户端强>
import socket
import sys
import datetime
from time import sleep
from client_sensordata import GetTemp
timeSleep = 10
def ClientSocket():
# Create a TCP/IP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Connect the socket to the port where the server is listening
server_address = ('192.168.2.3', 5560)
print >>sys.stderr, 'Connecting to: %s port: %s' % server_address
sock.connect(server_address)
try:
# Send data
name, humidity, temperature = GetTemp()
Sensorname = str(name)
temp = str(temperature)
hum = str(humidity)
print(Sensorname + ":" + temp + ":" + hum)
message = (Sensorname + ":" + temp + ":" + hum)
print("Transmitting data...")
print >>sys.stderr, 'Sending data...'
sock.send(str.encode(message))
# Look for the response
amount_received = 0
amount_expected = len(message)
while amount_received < amount_expected:
data = sock.recv(1024)
amount_received += len(data)
print >>sys.stderr, 'Send data'
finally:
print >>sys.stderr, 'Closing connection'
print >>sys.stderr, '------------------'
sock.close()
while True:
print("Start external server measurement at " + datetime.datetime.now().strftime("%H:%M:%S"))
ClientSocket()
sleep(timeSleep)
for t2 in range(5):
print("Start internal display measurement at " + datetime.datetime.now().strftime("%H:%M:%S"))
GetTemp()
print("------------------")
sleep(timeSleep)
循环5 cyclus用于内部测量(用于LCD显示器),然后将数据一次发送到服务器,将其存储在数据库(SQlite3)中。仍然希望添加更多功能(LED在读取时,在低于或超过限制时发出警告,警报声,LCD连接。当有进展时我会更新代码。
当然,欢迎任何提示和消息!