基于 Python Tornado 编写使用 TCP/IP 协议广播消息的简单的演示服务器
下面一段代码,演示了如何基于 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()