Python导入async tcp服务器作为模块:数据交换不起作用,使用模块进行多线程处理

时间:2017-03-31 11:12:05

标签: python multithreading asynchronous tcp server

我正在开发以下项目:我创建了一个异步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()

在这方面,我有以下问题:

  • 服务器的实例(serverTest = Server(address,dataFromSensor))必须在单独的线程中运行?
  • 为传感器创建一个新线程(ultrasonicTest = Ultrasonic()):

  • 在模块中运行线程是否更好(例如,在ultrasonic.py内启动线程而不是在main.py中)

  • 同步线程?

我是python的新手,我在多线程方面没有多少经验。如果有人在python中完成了一些类似的项目并且可以给我一些提示或类似项目的参考,那将会很有帮助。

0 个答案:

没有答案