螺纹Python TCP客户端类连续调用接收器方法和块发送方法



我希望标题合适。如果没有,请提出替代方案。我正在与以下Python客户班类合作。

import Queue
import socket
import struct
import threading
import time
class ClientCommand(object):
    CONNECT, SEND, RECEIVE, CLOSE = range(4)
    def __init__(self, type, data=None):
        self.type = type
        self.data = data
class ClientReply(object):
    ERROR, SUCCESS = range(2)
    def __init__(self, type, data = None):
        self.type = type
        self.data = data
class SocketClientThread(threading.Thread):
    def __init__(self, cmd_q = Queue.Queue(), reply_q = Queue.Queue()):
        super(SocketClientThread, self).__init__()
        self.cmd_q = cmd_q 
        self.reply_q = reply_q
        self.alive = threading.Event()
        self.alive.set()
        self.socket = None
        #self.stopped = False
        self.handlers = {
                ClientCommand.CONNECT: self._handle_CONNECT,
                ClientCommand.CLOSE: self._handle_CLOSE,
                ClientCommand.SEND: self._handle_SEND,
                ClientCommand.RECEIVE: self._handle_RECEIVE
                }
    def run(self):
        while self.alive.isSet():
            #while not self.stopped:
            try:
                cmd = self.cmd_q.get(True, 0.1)
                self.handlers[cmd.type](cmd)
            except Queue.Empty as e:
                continue
    def stop(self):
        self.alive.clear()
    def join(self, timeout=None):
        self.alive.clear()
        threading.Thread.join(self, timeout)
    def _handle_CONNECT(self, cmd):
        try:
            self.socket = socket.socket(
                    socket.AF_INET, socket.SOCK_STREAM)
            self.socket.connect((cmd.data[0], cmd.data[1]))
            self.reply_q.put(self._success_reply())
        except IOError as e:
            self.reply_q.put(self._error_reply(str(e)))
    def _handle_CLOSE(self, cmd):
        self.socket.close()
        reply = ClientReply(ClientReply.SUCCESS)
        self.reply_q.put(reply)

    def _handle_SEND(self, cmd):
        try:
            print "about to send: ", cmd.data
            self.socket.sendall(cmd.data)
            print "sending data"
            self.reply_q.put(self._success_reply())
        except IOError as e:
            print "Error in sending"
            self.reply_q.put(self._error_reply(str(e)))

    def _handle_RECEIVE(self, cmd):
         try:
             #TODO Add check for len(data)

            flag = True
            while flag:
                print "Receiving Data"
                data = self._recv_n_bytes()
                if len(data) != '':
                    self.reply_q.put(self._success_reply(data))
                if data == "Stop":
                    print "Stop command"
                    flag = False
         except IOError as e:
             self.reply_q.put(self._error_reply(str(e)))

    def _recv_n_bytes(self):
        data = self.socket.recv(1024)
        return data
    def _error_reply(Self, errstr):
        return ClientReply(ClientReply.ERROR, errstr)
    def _success_reply(self, data = None):
        return ClientReply(ClientReply.SUCCESS, data)

我的主要脚本代码 -

import socket
import time
import Queue
import sys
import os
from client import *
sct = SocketClientThread()
sct.start()
host = '127.0.0.1'
port = 1234

sct.cmd_q.put(ClientCommand(ClientCommand.CONNECT, (host, port)))
try:
    while True:
        sct.cmd_q.put(ClientCommand(ClientCommand.RECEIVE))

        reply = sct.reply_q
        tmp = reply.get(True)
        data = tmp.data
        if data != None:
            if data != "step1":
                //call function to print something
            else:
                // call_function that prints incoming data till server stops sending data 
                print "Sending OK msg"
                sct.cmd_q.put(ClientCommand(ClientCommand.SEND, "Hellon"))
            print "Done"
        else:
            print "No Data"
except:
    #TODO Add better error handling than a print
    print "Server down"

所以这是问题。线程启动并调用接收处理程序后,我将获得一些数据,如果该数据不是" step1",我只会调用函数(另一个脚本)以打印它。

但是,如果数据为" step1",我将调用一个函数,然后将继续打印服务器接下来发送的任何数据,直到服务器发送"停止"消息。在这一点上,我突破了"接收处理程序",并尝试向服务器发送"确定"消息。

但是,一旦我脱离"接收处理程序",它就会自动再次调用该功能。因此,当我试图发送一条消息时,客户端再次等待服务器的数据。因此,由于再次调用"接收器函数","发送函数"块。

我似乎不明白如何在接收和发送之间切换。我在这里的方法有什么问题?我应该如何解决这个问题?我需要重写代码以有两个单独的线程以发送和接收?

如果您需要更多详细信息,请在您决定无缘无故地提出问题之前让我知道。

但是,一旦我脱离了"接收处理程序", 自动调用该功能。

这是因为您在接收到的每个数据块的while True循环中调用sct.cmd_q.put(ClientCommand(ClientCommand.RECEIVE)),i。e。对于" step1"之前的每个数据,一个命令将调用"接收处理程序"(本身循环直到"停止")被放入客户端命令队列中,然后当然在发送命令之前执行这些命令。如果您在此while True循环之前将接收电话打开,您的方法可以工作。

错误是

    if msgid != "step1":
NameError: name 'msgid' is not defined

而不是

    #TODO Add better error handling than a print
    print "Server down"

你有更好的书面

    raise

并立即发现它。

最新更新