我正在开发以下项目:我创建了一个异步tcp tcp ip client / server连接。客户端(c#wpf GUI)将消息写入服务器(Raspberry pi,Python)并等待传感器数据。服务器从客户端接收消息并在循环中发回当前传感器数据。
服务器/客户端应用程序独立工作正常。在下一步中,我想在Python中使用模块。以下是我想在单独的Python文件中实现的主要部分:
Main.py
启动异步tcp服务器并在后台运行(线程)
打印从客户端收到的数据
这是python中我的代码(启动异步tcp服务器):
Main.py
import thread
import logging
import socket
import asyncore
#Import async server
from AsyncServerPi_Test import Server
if __name__=='__main__':
logging.basicConfig(level=logging.DEBUG,format='%(name)s: %(message)s',)
log = logging.getLogger('main')
#parameter
ip = socket.gethostname()
port = 12345
address = (ip, port) # port 0 means the kernel gives port
dataFromPi= 'SensorData'
server = Server(address,dataFromPi) #issue with parameter dataFromPI
#dataFromClient = server.getDataFromClient() Code is not working!
#log.debug(dataFromGUI)
asyncore.loop(timeout=1) # checks all client's readable/writable every second
AsyncServerPi_Test.py
import asyncore
import logging
import time
import socket
# Create one or more network channels -- instances of class asyncore.dispatcher.
# These channels are automatically added to a global map, used by the loop() function.
class Server(asyncore.dispatcher):
"""Receives connections and establishes handlers for each client."""
def __init__(self, address, dataFromPi):
self.dataFromPi = dataFromPi
self.logger = logging.getLogger('Server')
asyncore.dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.bind(address)
self.address = self.socket.getsockname()
self.logger.debug('binding to %s', self.address)
self.listen(1)
def timein(self):
self.start_time = time.time()
self.logger.debug('init start_time -> %e', self.start_time)
def handle_accept(self):
# Called when a client connects to our socket
client_info = self.accept()
if client_info is not None:
# start the timeout clock right away
self.timein()
self.logger.debug('handle_accept() -> %s', client_info[1])
Handler(client_info[0], self.start_time, self.dataFromPi)
def handle_close(self):
self.logger.debug('server_handle_close()')
self.close()
class Handler(asyncore.dispatcher):
"""Handles echoing messages from a single client. """
def __init__(self, sock, start_time, dataFromPi, chunk_size=1024):
self.dataFromPi = dataFromPi
self.start_time = start_time
# send data per 5 seconds
self.timeout = 5
self.chunk_size = chunk_size
self.logger = logging.getLogger('Handler%s' % str(sock.getsockname()))
asyncore.dispatcher.__init__(self, sock=sock)
self.data_to_write = []
def timeout_check(self):
#Time event
delta_t = time.time() - self.start_time
if delta_t > self.timeout:
self.logger.debug('timeout! -> %e %e', delta_t, self.timeout)
return True
else:
self.logger.debug('no timeout -> %e %e', delta_t, self.timeout)
return False
def trigger_close(self):
return self.timeout_check()
def writable(self):
"""We want to write if we have received data and when sendSensor data is on."""
# the trigger_close here is a hack
response = bool(self.data_to_write) or self.trigger_close()
self.logger.debug('writable() -> %s', response)
return response
def handle_write(self):
"""Write as much as possible of the reversed recent message we received."""
self.logger.debug('write data to GUI')
if self.trigger_close(): # hack to timeout socket
self.start_time = time.time()
#data = self.data_to_write.pop()
sent = self.send(dataFromPi)
return
data = self.data_to_write.pop()
sent = self.send(dataFromPi)
self.logger.debug('Send data to GUI:'+ str(sent))
#if sent < len(data)
#remaining = data[sent:]
#self.data_to_write.append(remaining)
#self.logger.debug('handle_write() -> (%d) "%s"', sent, data[:sent])
#if not self.writable(): # empty recv
#self.handle_close()
def reverse(self, s):
s = list(s)
s.reverse()
s = "".join(s)
return s
def handle_read(self):
"""Read an incoming message from the client and put it into our outgoing queue."""
data = self.recv(self.chunk_size)
self.logger.debug('handle_read() -> (%d) "%s"', len(data), data)
data = self.reverse(data)
self.data_to_write.insert(0, data)
#return self.data --> didnt work!
def handle_close(self):
"""server close only gets called if client decides or after timeout"""
self.logger.debug('handle_close()')
self.close()
我对参数dataFromPi和dataFromClient存在一些问题。 dataFromPi是我切换服务器实例的输入参数(server = Server(address,dataFromPi))。执行main.py文件时出现以下错误:
error: uncaptured python exception, closing channel <AsyncServerPi_Test.Handler connected 192.168.0.108:51028 at 0x31ba7d8> (<type 'exceptions.NameError'>:global name 'dataFromPi' is not defined [C:\Python27\lib\asyncore.py|write|91] [C:\Python27\lib\asyncore.py|handle_write_event|468] [C:\Python27\lib\AsyncServerPi_Test.py|handle_write|75])
Handler('192.168.0.108', 12345): handle_close()
我在AsyncServerPi_Test.py文件中检查了dataFromPi的切换,但我找不到解决方案。
我的下一个问题是我无法在main.py文件中打印dataFromClient。在AsyncServerPi_Test.py文件中,我可以读取dataFromClient(handle_read)。我试图在handle_read中返回收到的数据,但我认为数据的返回必须在类server()中进行。我如何能够证明服务器类从客户端返回数据,以便我可以在main.py中打印接收到的数据?
此外,服务器应该在后台运行,以便我可以并行运行其他操作(从超声波读取传感器数据,评估......)。作为一个例子,我希望main.py看起来应该类似:
import thread
import logging
import socket
import asyncore
#Import US
import Ultrasonic
#Import async tcp ip server
from AsyncServerPi_Test import Server
def main():
#Logging
logging.basicConfig(level=logging.DEBUG,format='%(name)s: %(message)s',)
log = logging.getLogger('main')
#Parameter for server
ip = socket.gethostname()
port = 12345
address = (ip, port) # port 0 means the kernel gives port
ultrasonicTest = Ultrasonic() # run in a seperate thread?
dataFromSensor = ultrasonicTest.readSensorData
serverTest = Server(address,dataFromSensor) # run in a seperate thread?
dataFromClient = serverTest.receivedData()
asyncore.loop(timeout=1) # checks all client's readable/writable every second
if __name__=='__main__':
main()
在这方面,我有以下问题:
为传感器创建一个新线程(ultrasonicTest = Ultrasonic()):
在模块中运行线程是否更好(例如,在ultrasonic.py内启动线程而不是在main.py中)
同步线程?
我是python的新手,我在多线程方面没有多少经验。如果有人在python中完成了一些类似的项目并且可以给我一些提示或类似项目的参考,那将会很有帮助。