如何从聊天服务器与多个客户端聊天

时间:2016-06-22 07:26:33

标签: python sockets console chat asyncore

问题:

  • 如何在os控制台中与聊天服务器中的任何用户客户端聊天?
  • 有人可以帮我多个客户的工作机制吗?作业机制由os终端控制台控制。

与服务器聊天

启动聊天服务器,并与客户建立聊天连接。

$ nc -v 127.0.0.1 4444 

双重客户如下:

 ====================     |---->  [client1: ('127.0.0.1', 37748)]
 | Server (Console) |<----|
 ====================     |---->  [client2: ('127.0.0.1', 37750)]


root@lab:/tmp# python ChatManager.py
start a chat server: ('127.0.0.1', 4444)
[+] client: ('127.0.0.1', 37748)
[+] client: ('127.0.0.1', 37750)
Hello World

当有多个客户端可用时,聊天服务器的控制台会发送“Hello World”,并显示

error: uncaptured python exception, closing channel <__main__.ConsoleHandler connected at 0xb73e96ec> 
(<type 'exceptions.OSError'>:  
[Errno 11] Resource temporarily unavailable  
[/usr/lib/python2.7/asyncore.py|read|83]  
[/usr/lib/python2.7/asyncore.py|handle_read_event|449]  
[ChatManager.py|handle_read|17] [/usr/lib/python2.7/asyncore.py|recv|387]  
[/usr/lib/python2.7/asyncore.py|recv|619])

ChatServer with multi clients

聊天服务器代码

#!/usr/bin/env python
# -*- coding: utf8 -*-

import asyncore
import sys


class ConsoleHandler(asyncore.file_dispatcher):
    """Enable console interactive for socket read/write.
    """
    def __init__(self, sender, file):
        asyncore.file_dispatcher.__init__(self, file)
        self.current_chat = sender
        self.BUFSIZE = 1024

    def handle_read(self):
        self.current_chat.out_buffer += self.recv(self.BUFSIZE)


class ChatManager(asyncore.dispatcher):
    """Handle tcp in-connections, ex: send commands to targets.
    """
    def __init__(self, _sock=None, _map=None):
        asyncore.dispatcher.__init__(self, _sock, _map)
        self.out_buffer = ''
        self.BUFSIZE = 1024

    def handle_read(self):
        data = self.recv(self.BUFSIZE)
        print(data.strip())
        # self.send(data)

    def handle_write(self):
        if self.out_buffer != "":
            sent = self.send(self.out_buffer)
            self.out_buffer = self.out_buffer[sent:]

    def handle_error(self):
        pass

    def handle_close(self):
        """Called when the socket is closed.
        """
        self.close()


class Listener(asyncore.dispatcher):
    """Start a tcp listener (default: 127.0.0.1:4444), and wait for connections.
       If a new connection, `ChatManager' will try to handle it.
    """
    def __init__(self, addr=('127.0.0.1', 4444), max_connections=4):
        asyncore.dispatcher.__init__(self)
        self.connections = []
        self.create_socket(asyncore.socket.AF_INET, asyncore.socket.SOCK_STREAM)

        self.set_reuse_addr()
        self.bind(addr)
        self.listen(max_connections)
        print('start a chat server: {}'.format(addr))

    def handle_accept(self):
        client, caddr = self.accept()
        print('[+] client: {}'.format(caddr))
        ConsoleHandler(ChatManager(client), sys.stdin)


if __name__ == "__main__":
    Listener()
    asyncore.loop()

1 个答案:

答案 0 :(得分:0)

这个self.set_reuse_addr()通常是一个坏主意,但对于开发来说很好。请尝试正确关闭您的连接。

我认为问题是你最终从ConsoleHandler中调用handle_read()两次(可能在那里放一个print("CH read")来检查代码的逻辑)。 要发送数据,请添加对handle_write的调用。

 def handle_read(self):
    self.current_chat.out_buffer += self.recv(self.BUFSIZE)
    self.current_chat.handle_write()

我将sent = self.send(self.out_buffer)更改为sent = self.send(bytes(self.out_buffer, encoding="utf-8"))