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