其中一个线程有时不会停止

时间:2014-04-25 15:04:27

标签: python multithreading sockets client

我有2个程序,一个是服务器侦听连接,然后接收数据并确认它们。这个很简单,我没有问题

import socket, sys, time
LEN = 32
class TCPserver:
    def __init__(self):
        server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        serverport = 11123
        server_socket.bind(("", serverport))    
        server_socket.listen(5)
        print "mimslistener waiting for client on server '%s' - port %s" % (socket.gethostname(),serverport)
        while 1:
            self.st = ""
            self.oldPktNo = -1
            self.client_socket, address = server_socket.accept()
            count = -1
            while 1:
                try:
                    count += 1
                    data = self.client_socket.recv(LEN)
                    # create error on the transmission
                    if count in [2, 8, 20,30,40]:
                        time.sleep(0.5)
                    elif count in [1, 5, 11, 13,23,33,43]:
                        continue         
                    sentStr = "{:{width}s}".format(self.checkData(data), width=16)
                    self.client_socket.send(sentStr)
                except socket.error, e:
                    print e
                    break

    def checkData(self, data):
        try:
            if int(data[0:10]) <= self.oldPktNo: 
                return "ACK%010d" % self.oldPktNo
            strdata = data[10:]
            self.st += strdata
            self.oldPktNo = int(data[0:10])
            return "ACK%010d" % self.oldPktNo
        except Exception,e:
            return "AGAIN" 

if __name__ == "__main__":
    TCPserver()            

第二个是客户端,我实现了2个线程。一个创建与服务器的连接,然后将数据发送到服务器,等待来自服务器的确认。另一个尝试每隔0.5秒检查一次监视器标志,如果看到状态正在等待来自服务器的ack(monitor = 0),它将重新发送该数据包。 (我不想检查发送所有数据,所以我省略了那个部分来缩短程序。)当点击'cancel'设置monitor = -1时,打算强制两个线程退出循环完成,sendPktThread等待1第二个用于monitorThread首先完成然后关闭连接。

from Tkinter import *
import Queue, threading
import socket, time, tkMessageBox
SEVERLEN = 32
LEN = SEVERLEN-10
prg = "001"
monitor = None
text ="""
[Verse 1]:You're the God of this City 
You're the King of these people 
You're the Lord of this nation You are 
[Chorus]For greater things have yet to come 
And greater things are still to be done in this City 
Greater thing have yet to come 
And greater things are still to be done in this City 
There is no one like our God There is no one like our God
"""
class TCPclient:
    def __init__(self, parent):
        self.parent = parent
        Button(self.parent, text="send lines", command=self.sendPktsCmd).pack(side=TOP)
        Button(self.parent, text="Alive State", command=self.aliveStatCmd).pack(side=TOP)
        Button(self.parent, text="cancel", command=self.cancelSendCmd).pack(side=TOP)
        self.sendingStatVar = StringVar()
        Label(self.parent, textvariable=self.sendingStatVar).pack(side=TOP, fill=X)

    def aliveStatCmd(self):
        print "thread0 alivestat=", self.thread0.isAlive()
        print "thread1 alivestat=", self.thread1.isAlive()

    def cancelSendCmd(self):
        global monitor
        monitor=-1

    def sendPktsCmd(self):
        global monitor
        self.data = self.split_by_len(text*3, LEN)
        self.totalPkts = len(self.data)
        self.no = 0

        self.setSendingState(self.totalPkts, 0) 
        self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.client_socket.connect(("localhost", 11123))

        self.client_socket.send( self.createPkt(self.data[self.no], self.no) )
        monitor = 1
        receivedNo = -1
        self.queue = Queue.Queue()
        self.thread0 = ThreadedTask(self.queue, self, 0)
        self.thread0.start()
        self.thread1 = ThreadedTask(self.queue, self, 1)
        self.thread1.start()


    def monitorThread(self):
        global monitor
        if monitor == 1:
            try:
                self.client_socket.send( self.createPkt(self.data[self.no], self.no) )
            except Exception, e:
                print "error in monitorThread: ", e
                self.result = -1
                monitor = -1


    def sendPktsThread(self):
        global monitor
        try:
            data = self.client_socket.recv(16)
            print data
            if monitor!=-1: monitor = 0
            if (data[:3] == 'ACK'):
                try:
                    receivedNo = int(data[3:14])
                except: pass
                if self.no == receivedNo:
                    self.no = self.no + 1

                self.setSendingState(self.totalPkts, self.no)
            self.client_socket.send( self.createPkt(self.data[self.no], self.no) )
            if monitor!=-1: monitor = 1

        except Exception, e:
            print "error in sendPktsThread:",e
            self.result = -1
            monitor = -1

    def setSendingState(self, totalPkts, pktNo=None):
        msg = "Sending %s/%s." % (pktNo, totalPkts)
        self.sendingStatVar.set(msg)
        self.parent.update()

    def createPkt(self, st, pktNo):          
        pktNoStr = "%010d" % pktNo # 10
        return pktNoStr + st         

    def split_by_len(self, text, n):
        data = ["".join(text[i:i+n]) for i in range(0, len(text), n)]
        data[-1] = "{:{width}s}".format(data[-1],width=n)
        return data


class ThreadedTask(threading.Thread):
    def __init__(self, queue, parent, funcalled):
        threading.Thread.__init__(self)
        self.queue = queue
        self.parent = parent
        self.funcalled = funcalled

    def run(self):
        global monitor
        while monitor!=-1:
            if self.funcalled == 0 : 
                print "sendPktsThread monitor=", monitor
                self.parent.sendPktsThread()
            else:
                print "monitorThread monitor=", monitor
                time.sleep(0.5)
                self.parent.monitorThread()

        if self.funcalled == 0 : 
            time.sleep(1)
            self.parent.client_socket.close()
            print "Done with sendPktsThread - monitor=%s" % monitor
        else: 
            print "Done with monitorThread - monitor=%s" % monitor


root = Tk()
root.title("Test Button")
main_ui = TCPclient(root)
root.mainloop()

然而有时,只有一个线程完成,我不知道其他线程当时在做什么。任何人都可以向我解释并帮助我解决方案吗?

(测试:首先运行服务器程序,然后运行客户端程序。单击“发送行”开始发送数据,然后单击“取消”停止发送数据。单击“活动状态”以检查哪些线程仍处于活动状态对于前几个“发送行”和“取消”,你可以得到两个线程的状态为False(这是我所期望的。大约第3或第4次,其中一个线程将为True)

1 个答案:

答案 0 :(得分:0)

我发现了问题所在。那是服务器丢失了一些数据包并且没有发送ACK的时候。如果monitorThread因为monitor flag = -1而已经停止,则程序无法重新发送数据包。 sendPktsThread一直在等待接收ACK并且永远不会得到它。所以我改变程序让monitorThread继续重发数据包,直到sendPktsThread完全停止。

def monitorThread(self):
    global monitor
    try:
        self.client_socket.send( self.createPkt(self.data[self.no], self.no) )
    except Exception, e:
        print "error in monitorThread: ", e
        self.result = -1
        monitor = -2
在ThreadedTask中

def run(self):
    global monitor
    if self.funcalled == 0:
        while monitor > -1:
            self.parent.sendPktsThread()
        print "Done with sendPktsThread - monitor=%s" % monitor
        monitor = -2
    else:
        while monitor > -2:
            time.sleep(0.5)
            self.parent.monitorThread()  
        print "Done with monitorThread - monitor=%s" % monitor
        self.parent.client_socket.close()