当没有数据从服务器接收时,python客户端挂起,挂起在线程中,不允许客户端发送数据

当没有数据从服务器接收时,python客户端挂起,挂起在线程中,不允许客户端发送数据,python,multithreading,client,locking,Python,Multithreading,Client,Locking,我正试图弄清楚如何让我的客户机“同时”发送和接收数据,并且正在使用线程。我的问题是,根据我设置它的方式,它在ReceiveFromServer函数中等待来自服务器的数据的方式,该函数位于它自己的线程中,并且在没有发送任何内容时无法停止它。另一种方式是,它只是等待用户输入,然后发送到服务器,然后在客户端向服务器发送消息后调用ReceiveFromServer函数,该消息不允许流畅的通信,但无法使其自动切换。当客户端没有任何东西要发送,或者服务器没有更多的东西要接收时,如何释放线程 如果我试着解释我

我正试图弄清楚如何让我的客户机“同时”发送和接收数据,并且正在使用线程。我的问题是,根据我设置它的方式,它在ReceiveFromServer函数中等待来自服务器的数据的方式,该函数位于它自己的线程中,并且在没有发送任何内容时无法停止它。另一种方式是,它只是等待用户输入,然后发送到服务器,然后在客户端向服务器发送消息后调用ReceiveFromServer函数,该消息不允许流畅的通信,但无法使其自动切换。当客户端没有任何东西要发送,或者服务器没有更多的东西要接收时,如何释放线程

如果我试着解释我试过的每一件事,时间会很长。:)

谢谢

客户:

from socket import *
from threading import *
import thread
import time
from struct import pack,unpack
from networklingo import *
#from exception import *

HOST = '192.168.0.105'
PORT = 21567
BUFFSIZE = 1024
ADDR = (HOST,PORT)

lock = thread.allocate_lock()

class TronClient:

    def __init__(self,control=None):
        self.tcpSock = socket(AF_INET,SOCK_STREAM)
        #self.tcpSock.settimeout(.2)
        self.recvBuff = []

    def connect(self):
        self.tcpSock.connect(ADDR)
        self.clientUID = self.tcpSock.recv(BUFFSIZE)
        print 'My clientUID is ', self.clientUID
        t = Thread(target = self.receiveFromSrv())
        t.setDaemon(1)
        t.start()
        print 'going to main loop'
        self.mainLoop()
        #t = Thread(target = self.mainLoop())
        #t.setName('mainLoop')
        #t.setDaemon(1)
        #t.start()

    def receiveFromSrv(self):
        RECIEVING = 1
        while RECIEVING:
            #print 'Attempting to retrieve more data'
            #lock.acquire()
            #print 'Lock Aquired in recieveFromSrv'

            #try:
            data = self.tcpSock.recv(BUFFSIZE)
            #except socket.timeout,e:
                    #print 'Error recieving data, ',e
                    #continue
            #print data
            if not data: continue

            header = data[:6]
            msgType,msgLength,clientID = unpack("hhh",header)
            print msgType
            print msgLength
            print clientID,'\n'

            msg = data[6:]

            while len(msg) < msgLength:
                data = self.tcpSock.recv(BUFFSIZE)
                dataLen = len(data)

                if dataLen <= msgLength:
                    msg += data
                else:
                    remLen = msgLength-len(data) #we just need to retrieve first bit of data to complete msg 
                    msg += data[:remLen]
                    self.recvBuff.append(data[remLen:])

            print msg
            #else:
                #lock.release()
            #    print 'lock release in receiveFromSrv'
                #time.sleep(2)
            #RECIEVING = 0

    def disconnect(self,data=''):
        self.send(DISCONNECT_REQUEST,data)
        #self.tcpSock.close()

    def send(self,msgType,msg):
        header = pack("hhh",msgType,len(msg),self.clientUID)
        msg = header+msg
        self.tcpSock.send(msg)

    def mainLoop(self):
        while 1:
            try:
                #lock.acquire()
                #print 'lock aquired in mainLoop'
                data = raw_input('> ')
            except EOFError:            # enter key hit without any data (blank line) so ignore and continue
                continue                

            #if not data or data == '':  # no valid data so just continue
            #    continue

            if data=='exit':            # client wants to disconnect, so send request to server
                self.disconnect()
                break
            else:
                self.send(TRON_CHAT,data)

            #lock.release()
            #print 'lock released in main loop'
            #self.recieveFromSrv()
            #data = self.tcpSock.recv(BUFFSIZE)
            #t = Thread(target = self.receiveFromSrv())
            #t.setDaemon(1)
            #t.start()



if __name__ == "__main__":
    cli = TronClient()
    cli.connect()
    #t = Thread(target = cli.connect())
    #t.setName('connect')
    #t.setDaemon(1)
    #t.start()
从套接字导入*
从线程导入*
导入线程
导入时间
从结构导入包中,解压缩
从networklingo导入*
#从异常导入*
主机='192.168.0.105'
端口=21567
BUFFSIZE=1024
地址=(主机,端口)
lock=thread.allocate_lock()
客户类别:
def __;初始(自身,控制=无):
self.tcpSock=socket(AF\u INET,SOCK\u STREAM)
#self.tcpSock.settimeout(.2)
self.recvBuff=[]
def连接(自):
self.tcpSock.connect(ADDR)
self.clientUID=self.tcpSock.recv(BUFFSIZE)
打印'My clientUID is',self.clientUID
t=线程(目标=self.receiveFromSrv())
t、 setDaemon(1)
t、 开始()
打印“转到主循环”
self.mainLoop()
#t=线程(目标=self.mainLoop())
#t、 setName('mainLoop')
#t、 setDaemon(1)
#t、 开始()
从SRV接收的def(自身):
接收=1
接收时:
#打印“正在尝试检索更多数据”
#lock.acquire()
#打印“从SRV接收到的锁”
#尝试:
数据=self.tcpSock.recv(BUFFSIZE)
#套接字除外。超时,e:
#打印“接收数据时出错”,e
#继续
#打印数据
如果没有数据:继续
标题=数据[:6]
msgType,msgLength,clientID=unpack(“hhh”,标题)
打印msgType
打印msgLength
打印客户端ID,'\n'
msg=数据[6:]
而len(msg)如果dataLen我想您应该尝试将套接字设置为非阻塞模式:

设置设备的阻塞或非阻塞模式 套接字:如果标志为0,则套接字 设置为非阻塞,否则设置为 阻塞模式。最初,所有插座 处于阻塞模式。非阻塞 模式,如果recv()调用找不到 任何数据,或者如果send()调用无法 立即处理数据,然后 引发错误异常;拦网 模式下,调用将阻塞,直到它们可以 继续s、 设置锁定(0)为 相当于s.settimeout(0); s、 设置锁定(1)相当于 s、 设置超时(无)


此外,您还考虑过使用模块,而不是使用原始套接字。它是进行网络IO的更高级别抽象。上的部分专门用于在客户端/服务器之间发送和接收数据。

感谢您的回复。在recv调用之前,我已经尝试过self.tcpSock.setblocking(0),但是似乎没有什么区别,并且(目前)将其保留在服务器代码中。我一直在研究多处理模块,您是否知道,在我刚刚学习python时,将其与我已有的模块集成是否容易?我不确定我将如何使用这些方法之一。提前谢谢你的帮助。
from socket import *
from threading import *
import thread
from controller import *
from networklingo import *
from struct import pack,unpack

HOST = ''
PORT = 21567
BUFSIZE = 1024
ADDR = (HOST,PORT)

nclntlock = thread.allocate_lock()

class TronServer:

    def __init__(self,maxConnect=4,control=None):
        self.servSock = socket(AF_INET,SOCK_STREAM)

        # ensure that you can restart server quickly when it terminates
        self.servSock.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)

        self.servSock.bind(ADDR)
        self.servSock.listen(maxConnect)

        # keep track of number of connected clients
        self.clientsConnected = 0

        # give each client a unique identfier for this run of server
        self.clientUID = 0

        # list of all clients to cycle through for sending
        self.allClients = {}

        # keep track of threads
        self.cliThreads = {}

        #reference back to controller
        self.controller = control

        self.recvBuff = []

    def removeClient(self,clientID,addr):
        if clientID in self.allClients.keys():
            self.allClients[clientID].close()
            print "Disconnected from", addr
            nclntlock.acquire()
            self.clientsConnected -= 1
            nclntlock.release()
            del self.allClients[clientID]
        else:
            print 'ClientID is not valid'

    def recieve(self,clientsock,addr):
        RECIEVING = 1

        # loop serving the new client
        while RECIEVING: # while PLAYING???
            try:
                data = clientsock.recv(BUFSIZE)
            except:
                RECIEVING = 0
                continue

#            if not data: break  #no data was recieved

            if data != '':
                print 'Recieved msg from client: ',data

                header = data[:6]
                msgType,msgLength,clientID = unpack("hhh",header)
                print msgType
                print msgLength
                print clientID,'\n'

                if msgType == DISCONNECT_REQUEST:               #handle disconnect request
                    self.removeClient(clientID,addr)
                else:                                           #pass message type and message off to controller

                    msg = data[6:]

                    while len(msg) < msgLength:
                        data = self.tcpSock.recv(BUFSIZE)
                        dataLen = len(data)

                        if dataLen <= msgLength:
                            msg += data
                        else:
                            remLen = msgLength-len(data) #we just need to retrieve first bit of data to complete msg 
                            msg += data[:remLen]
                            self.recvBuff.append(data[remLen:])

                    print msg       
            # echo back the same data you just recieved
            #clientsock.sendall(data)
                    self.send(TRON_CHAT,msg,-1) #send to client 0


        for k in self.allClients.keys():
            if self.allClients[k] == clientsock:
                self.removeClient(k,addr)
                print 'deleted after hard exit from clientID ', k
                #self.cliThreads[k].join()
                #del self.cliThreads[k]
                # then tell controller to delete player with k
                break

    def send(self,msgType,msg,clientID=-1):
        header = pack("hhh",msgType,len(msg),clientID)
        msg = header+msg

        if clientID in self.allClients:
            self.allClients[clientID].send(msg)
        elif clientID==ALL_PLAYERS:
            for k in self.allClients.keys():
                self.allClients[k].send(msg)


    def mainLoop(self):
        global nclntlock

        try:
            while self.controller != None and self.controller.state == WAITING:
                print 'awaiting connections'
                clientsock, caddy = self.servSock.accept()

                nclntlock.acquire()                         
                self.clientsConnected += 1
                nclntlock.release()
                print 'Client ',self.clientUID,' connected from:',caddy
                clientsock.setblocking(0)
                clientsock.send(str(self.clientUID))
                self.allClients[self.clientUID] = clientsock
                t = Thread(target = self.recieve, args = [clientsock,caddy])
                t.setName('recieve-' + str(self.clientUID))
                self.cliThreads[self.clientUID] = t
                self.clientUID += 1
                # t.setDaemon(1)
                t.start()
        finally:
            self.servSock.close()

if __name__ == "__main__":
    serv = TronServer(control = LocalController(nPlayers = 3, fWidth = 70, fHeight = 10))
    t = Thread(target = serv.mainLoop())
    t.setName('mainLoop')
#   t.setDaemon(1)
    t.start()