2016-03-01 53 views
0

我开始使用套接字编写python代码,并且我的聊天脚本有点问题。python socket tchat问题

服务器脚本

import pickle, socket, struct, sys, threading 

SERVERADDRESS = ("localhost", 6030) 

class helloChatServer(threading.Thread): 

    def __init__(self): 
     threading.Thread.__init__(self) 
     self.__server = socket.socket() 
     self.users = [] 

     try: 
      self.__server.bind(SERVERADDRESS) 
     except socket.error: 
      print('Bind failed {}'.format(socket.error)) 

     self.__server.listen(10) 

    def exit(self): 
     self.__server.close() 

    def run(self): 
     print("Listening... {}".format(SERVERADDRESS)) 
     while True: 
      client, addr = self.__server.accept() 
      try: 
       threading.Thread(target=self._handle, args=(client, addr)).start() 
      except OSError: 
       print('Error during processing the message') 


    def _handle(self, client, addr): 
     print('Client connected with {}:{}'.format(addr[0], str(addr[1]))) 
     self.users.append(addr) 

     while True: 

      data = client.recv(1024) 
      print(data) 
      client.send(data) 

     client.close() 

if __name__ == '__main__': 

    helloChatServer().run() 

客户端脚本

import pickle, socket, struct, sys, threading 

SERVERADDRESS = (socket.gethostname(), 6050) 

class helloChatClient(): 

    def __init__(self, host='localhost', port=5000, pseudo="Visitor"): 
     self.__socket = socket.socket() 
     self.__socket.bind((host, port)) 
     self.__pseudo = pseudo 

     print('Listening on {}:{}'.format(host, port)) 

    def run(self): 
     handlers = { 
      '/exit': self._exit, 
      '/quit': self._quit, 
      '/join': self._join, 
      '/send': self._send 
     } 
     self.__running = True 
     self.__address = None 
     threading.Thread(target=self._receive).start() 
     while self.__running: 
      line = sys.stdin.readline().rstrip() + ' ' 
      # Extract the command and the param 
      command = line[:line.index(' ')] 
      param = line[line.index(' ')+1:].rstrip() 
      # Call the command handler 
      if command in handlers: 
       try: 
        handlers[command]() if param == '' else handlers[command](param) 
       except: 
        print("Error during the execution of the message") 
      else: 
       print('Command inconnue:', command) 

    def _exit(self): 
     self.__running = False 
     self.__address = None 
     self.__socket.close() 

    def _quit(self): 
     self.__address = None 

    def _join(self, param): 
     if self.__pseudo == "Visitor": 
      self.__pseudo = input("Choose a username: ") 

     tokens = param.split(' ') 
     if len(tokens) == 2: 
      try: 
       self.__address = (tokens[0], int(tokens[1])) 
       self.__socket.connect(self.__address) 
       print('~~~~~~~~~~~~~~~~~~~~~~~~~~') 
       print('Connected at {}:{}'.format(*self.__address)) 
       print('~~~~~~~~~~~~~~~~~~~~~~~~~~') 
      except OSError: 
       print("Error during the sending of the message") 

     self.__socket.send(self.__pseudo.encode()) 

    def _send(self, param): 
     if self.__address is not None: 
      try: 
       message = param.encode() 
       totalsent = 0 
       while totalsent < len(message): 
        sent = self.__socket.send(message[totalsent:]) 
        totalsent += sent 
       print(self.__socket.recv(1024).decode()) 
      except OSError: 
       print('Error during the reception of the message') 

    def _receive(self): 
     while self.__running: 
      try: 
       data = self.__socket.recv(1024).decode() 
       print(data) 
      except socket.timeout: 
       pass 
      except OSError: 
       return 


if __name__ == '__main__': 

    if len(sys.argv) == 4: 
     helloChatClient(sys.argv[1], int(sys.argv[2]), sys.argv[3]).run() 
    else: 
     helloChatClient().run() 

好吧,当我在终端上运行脚本,我看到这一点。

服务器

MacBook-Pro-de-Saikou:labo2 saikouah$ python3.4 helloChatServer.py 
En écoute sur... ('MacBook-Pro-de-Saikou.local', 6030) 
Client connected with 127.0.0.1:5004 
Il y a actuellement 1 connecté 
b'bluebeel' 
b'hello' 

客户

MacBook-Pro-de-Saikou:labo2 saikouah$ python3.4 helloChatClient.py localhost 5004 bluebeel 
Écoute sur localhost:5004 
/join MacBook-Pro-de-Saikou.local 6030 
~~~~~~~~~~~~~~~~~~~~~~~~~~ 
Connecté à MacBook-Pro-de-Saikou.local:6030 
~~~~~~~~~~~~~~~~~~~~~~~~~~ 
/send hello 
bluebeel 

在客户端,他不打印我打招呼,但bluebeel。我做了几次测试,每次收到前一封邮件时,他都会带我。看起来他迟到了。

有人可以帮助我吗? :)

回答

0

故障分析

你的代码没有在_receive功能:

data = self.__socket.recv(1024).decode() 

此行抛出OSError因为你试图调用.recv之前连接到服务器。因此异常处理程序被触发并且函数退出。那么,什么情况是,调用

threading.Thread(target=self._receive).start() 

功能_receive退出后,之前你叫/join。所以看看会发生什么

  1. 您可以拨打/join
  2. bluebeel被发送到
  3. 服务器接收它,并将其发送回客户端
  4. _receive功能不再存在的服务器。因此,该消息在插座上的“堆叠”(它会等待下一次.recv()调用)
  5. 你叫/send hello
  6. 服务器接收hello并将其发送回
  7. 客户端调用print(self.__socket.recv(1024).decode())_send方法
  8. .recv检索堆叠在插座上的第一条消息。在这种情况下,它不是hello,它是bluebeel

现在这个模式继续工作。您发送消息,服务器将其回送,但接收到的消息前面始终有1条消息。 “迟到”消息。


SOLUTION

一个解决这个问题的方法是调用

threading.Thread(target=self._receive).start() 

._join方法.connect后。请记得从_send方法中删除print(self.__socket.recv(1024).decode()),否则将阻止stdin

当然,您在发出多个/join命令时会遇到问题。要正确解决这个问题,你必须跟踪_receive线程,并在._join方法开始时将其终止。但这超出了恕我直言这个问题的范围。


边注

永远不要处理异常像你这样。这是错误的:

try: 
    data = self.__socket.recv(1024).decode() 
    print(data) 
except socket.timeout: 
    pass 
except OSError: 
    return 

至少做到这一点:

import traceback 

try: 
    data = self.__socket.recv(1024).decode() 
    print(data) 
except socket.timeout: 
    traceback.print_exc() 
except OSError: 
    traceback.print_exc() 
    return