2010-02-13 2 views
0

내 클라이언트가 '동시에'데이터를 보내고받을 수있는 방법을 찾고 스레드를 사용하고 있습니다. 내 문제는 내가 그것을 설정하는 방법에 따라 여기에 그것은 자체 스레드에있는 recieveFromServer 함수에서 서버로부터 데이터를 기다리고 아무 것도 보내지 않을 때 멈출 수 없다는 것이다. 클라이언트가 유창한 통신을 허용하지 않는 서버에 메시지를 보낸 후에 recieveFromServer 함수를 호출하지만 자동으로 대체 할 수는 없습니다. . 클라이언트가 아무 것도 전송되지 않거나 더 이상 서버로부터 수신 할 수 없을 때 스레드를 어떻게 해제합니까?파이썬 클라이언트가 서버에서 수신 할 데이터가 없을 때 응답을 보내고 클라이언트가 보내지 않고 해당 스레드에 멈춤

내가 시도한 모든 것을 설명하려고하면 오랜 시간이 걸릴 것입니다. :)

감사합니다.

클라이언트 :

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() 

서버 (증가 또는 클라이언트의 수를 감소시키는 경우 잠금을 사용) :

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() 

답변

2

난 당신이 시도하고 비 - 블로킹 (non-blocking) 소켓을 설정하려는 생각을 모드 :

http://docs.python.org/library/socket.html#socket.socket.setblocking

,536,

소켓의 차단 또는 비 차단 모드를 설정합니다. flag가 0이면 소켓 이 차단되지 않음으로 설정되고 그렇지 않으면 차단 모드로 설정됩니다. 처음에는 모든 소켓 이 차단 모드에 있습니다. 비 블록화 모드에서 recv() 호출이 데이터를 찾지 못하거나 send() 호출이 데이터를 즉시 처리 할 수없는 경우 오류 예외가 발생합니다. 블로킹 모드에서는 호출이 차단 될 때까지 이 진행됩니다. s.setblocking (0)은 이고 s.settimeout (0)과 같습니다. s.setblocking (1)은 s.settimeout (없음)과 같습니다.

또한 원시 소켓을 사용하는 대신 multiprocessing 모듈을 사용하여 협의했습니다. 네트워크 IO를 수행하는 데 더 높은 수준의 추상화입니다. Pipes & Queues 섹션은 클라이언트/서버간에 데이터를 보내고받는 데 사용됩니다.

+0

감사합니다. recv 호출 전에 self.tcpSock.setblocking (0) 시도했지만 아무런 차이를 만들 것 및 어쨌든 (현재) 서버 코드에서 유지 된 것 같습니다. 다중 처리 모듈을 살펴 봤는데 파이썬을 배우면서 이미 가지고있는 모듈과 쉽게 통합 할 수 있는지 알고 있습니까? 나는이 방법들 중 하나를 어떻게 사용하는지 정확히 모르겠습니다. 도움을 미리 감사드립니다. – Devin

관련 문제