通过python

时间:2018-04-06 11:26:35

标签: python raspberry-pi tcpclient tcp-ip tcpserver

大家好,

我遇到了一些套接字通信编码的问题。我有两个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

有人可以提供一些提示或帮助,或者告诉我为什么要解决这个问题?我已搜索过多个帖子和其他帖子,但无法找到解决方案。

提前感谢您提供的每一项帮助。

3 个答案:

答案 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

我还建议您在新线程中处理数据传输(),以便能够连续处理连续的传入连接。

以下是参考:https://docs.python.org/2/howto/sockets.html

答案 1 :(得分:0)

我建议不要重复关闭和打开新的套接字,而是建议维护多个打开的套接字连接服务器端并使用select()方法处理每个套接字。

https://docs.python.org/2/library/select.html

https://pymotw.com/2/select/

Can a server handle multiple sockets in a single thread?

答案 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连接。当有进展时我会更新代码。

当然,欢迎任何提示和消息!