簡體   English   中英

線程化的Python TCP Client類不斷調用Receiver方法並阻止Send方法

[英]Threaded Python TCP Client Class continuously calls Receiver method and blocks Send method

我希望標題合適。 如果沒有,請提出一個替代方案。 我正在使用以下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, "Hello\n"))

            print "Done"
        else:
            print "No Data"

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

這就是問題所在。 一旦線程啟動,並調用了接收處理​​程序,我將獲得一些數據,如果該數據不是“ Step1”,則只需調用一個函數(另一個腳本)進行打印即可。

但是,如果數據是“ step1”,則我調用一個函數,該函數將繼續打印服務器接下來發送的任何數據,直到服務器發送“ Stop”消息。 在這一點上,我突破了“接收處理程序”,並嘗試向服務器發送“ Ok”消息。

但是,一旦我脫離“接收處理程序”,它就會自動再次調用該函數。 因此,當我嘗試發回郵件時,客戶端再次在等待來自服務器的數據。 因此,由於再次調用了“接收器功能”,因此“發送功能”將阻塞。

我似乎無法理解如何在接收和發送之間切換。 我在這里的方法有什么問題,應該如何解決? 我是否需要重新編寫代碼以具有用於發送和接收的兩個單獨的線程?

如果您需要更多詳細信息,請在決定無故標記我的問題之前讓我知道。

但是,一旦我脫離“接收處理程序”,它就會自動再次調用該函數。

這是因為您在while True循環中調用了sct.cmd_q.put(ClientCommand(ClientCommand.RECEIVE)) ,該循環針對接收到的每個數據塊(即“ step1”之前的每個數據)運行另外一個命令來調用“接收”將“處理程序”(自身循環直到“停止”)放入ClientCommand隊列中,然后當然要在SEND命令之前執行這些命令。 如果while True循環之前將RECEIVE調用放置在此位置之前,則您的方法可以使用。

錯誤是

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

代替

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

你最好寫

    raise

並立即發現它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM