基于 Python Tornado 编写使用 TCP/IP 协议广播消息的简单的演示服务器

2021-08-19
1分钟阅读时长

下面一段代码,演示了如何基于 Python 的 Tornado 框架编写一个简单的使用 TCP/IP 协议在客户端之间广播消息的服务器。可用来实现简单的聊天服务器。

#!/usr/bin/env python
# encoding: utf-8

import socket

from tornado.tcpserver import TCPServer
from tornado.options import define
from tornado.options import options
from tornado.ioloop import IOLoop

# 定义命令行参数
define("host", default="0.0.0.0", help="run on the given host(or ip)", type=str)
define("port", default=8056, help="run on the given port", type=int)

class ClientConnection(object):
    """
    客户端的连接
    """
    def __init__(self, stream, address):
        self.stream = stream
        self.address = address
        self.stream.set_close_callback(self.on_close)

        print self.address, " connection!"

        # 添加一个定时器,或者信号等,用来:
        # 有数据准备好读时,读取命令(或数据),解析并处理
        # 全局数据索引变化时,获取最新的聊天记录,并发送

        IOLoop.current().add_handler(self.stream.fileno(), self.on_read, IOLoop.READ)

        self.read()

    def on_read(self, fd, events):
        #print "fd: ", fd, " events: ", events
        pass

    def read(self):
        self.stream.read_until('\n', self.handle)

    def send(self, data):
        """
        发送数据
        :param data:
        :return:
        """
        self.stream.write(data)

    def handle(self, data):
        """
        和连接的交互 - 接受请求并分析,发送广播信息
        :param data:
        :return:
        """
        data = data.replace('\r', '')
        data = data.replace('\n', '')

        if data == "quit" or data == "exit":
            self.stream.close()
            return

        # 接受数据
        ChatServer.messages.append(data)

        # 广播消息
        for conn in ChatServer.connections:
            conn.send(data)

        self.read()

    def on_close(self):
        """
        退出时的处理
        :return:
        """
        print self.address, " quit the connection"
        ChatServer.connections.remove(self)


class ChatServer(TCPServer):
    """
    聊天服务器全局类
    """

    connections = set()
    messages = []

    def __init__(self, host, port):
        super(ChatServer, self).__init__()

        self.host = host
        self.port = port

        self.msgs = []
        self.clients = set()

    def handle_stream(self, stream, address):
        """
        一个新的链接
        :param stream:
        :param address:
        :return:
        """
        print "%s - %s:%s" % (stream, address[0], address[1])

        # 设置 socket 的 KEEPALIVE
        stream.socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
        # stream.socket.setsockopt(socket.SOL_TCP, socket.TCP_KEEPIDLE, 60)
        stream.socket.setsockopt(socket.SOL_TCP, socket.TCP_KEEPINTVL, 5)
        stream.socket.setsockopt(socket.SOL_TCP, socket.TCP_KEEPCNT, 20)

        client = ClientConnection(stream, address)

        ChatServer.connections.add(client)

def main():
    options.parse_command_line()

    host = options.host
    port = options.port

    print "%s : %s" % (host, port)

    server = ChatServer(host, port)

    # `listen`: simple single-process::
    server.listen(server.port, address=server.host)
    IOLoop.current().start()


if __name__ == '__main__':
    main()
Avatar

JeffWu Author

数十年互联网从业经验,互联网全栈开发工程师,资深技术管理人员,资深游戏开发工程师。具有丰富的搭建海量数据处理系统的经验,大容量、高并发、高可靠线上运营系统的搭建和维护的丰富经验。