In the frame of the tornado is mainly introduced in this paper, using the tcpserver, tcpclient, struct. The pack (), struct. Unpack realization of a simple echo server.

In network communication, binary stream data needs to be sent; The struct.pack() function is responsible for the data group package, which combines data according to a specified transport protocol; The struct.unpack() function is responsible for unpacking the data, which is to break it up according to a specified protocol.

Without saying much, let’s take a look at the specific implementation code.

The TCP client code is as follows:

# coding=utf-8 import struct import logging from tornado import ioloop, Gen from Tornado.tcpclient import tcpclient """ tcpclient-struct.pack() group sends packet format: header + body Message: Message sender (4 bytes)+ Message receiver (4 bytes)+ Message type (1 byte)+ Data length in message body (4 bytes) Message body: Struct.unpack () Receive packet format: Message header + message body Message header: message sender (4 bytes)+ message type (1 byte)+ length of data in message body (4 bytes) Message body: data to be received """ logging.basicConfig(level= logging.debug) logger = logging.getLogger(__name__) class ChatClient(object): def __init__(self, host, port): self.host = host self.port = port @gen.coroutine def start(self): self.stream = yield TCPClient().connect(self.host, self.port) while True: yield self.send_message() yield self.receive_message() @gen.coroutine def send_message(self): MSG = input(" input :") bytes_msg = bytes(msg.encode("utf-8") Msg_type = 1 binary_msg = struct. Pack ("! IIBI"+str(len(msg))+"s", chat_id, receive_id, msg_type, len(msg), Write (binary_msg) @gen. Coroutine def receive_message(self): "" """ try: logger.debug("receive data ..." Sender = yield self.stream. Read_bytes (4, partial=True) sender = struct.unpack('! I', sender)[0] logger.debug(' sender:%s ', sender) # yield self.stream. Read_Bytes (1, 1) partial=True) msg_type = struct.unpack('! B', msg_type)[0] logger.debug("msg_type:%s", msg_type) # yield self.stream. Read_bytes (4, 1) partial=True) msg_len = struct.unpack('! I', msg_len)[0] logger.debug("msg_len:%s", msg_len) = yield self.stream. Read_bytes (msg_len) partial=True) data = struct.unpack("!" + str(msg_len) + "s", data) logger.debug("data:%s", data) except Exception as e: logger.error("tcp client exception:%s", e) def main(): C1 = ChatClient c1 (" 127.0.0.1 ", 8888). The start () ioloop. Ioloop. The instance (). The start () if __name__ = = "__main__ ': the main ()

TCP server code:

# coding=utf-8 import struct import logging from tornado.tcpserver import TCPServer from tornado.netutil import bind_sockets from tornado.iostream import StreamClosedError from tornado import gen from tornado.ioloop import IOLoop Message Message Header: Message sender (4 bytes)+ Message receiver (4 bytes)+ Message type (1 byte)+ Data length in message body (4 bytes) Message body: Data to be received Struct.pack() group packet forwarding packet format: message header + message body Message header: message sender (4 bytes)+ message type (1 byte)+ data length in message body (4 bytes) Message body: data to be sent "" logging.basicConfig(level=logging.DEBUG) logger = logging.getLogger(__name__) class ChatServer(TCPServer): PORT = 8888 clients = dict() @gen. Coroutine def handle_stream(self, stream, address): "" :param address: :return: "" logger.debug("%s ", address) ChatServer. Clients [address] = stream while True: try: #! Sender = yield stream. Read_bytes (4, partial=True) Sender = struct.unpack('! I', sender)[0] logger. Debug ("sender:%s", sender) # yield stream. Read_bytes (4, 1) partial=True) receiver = struct.unpack('! (" Receiver :%s", "Receiver")[0] logger.debug(" Receiver :%s", "Receiver")[0] logger.debug(" Receiver :%s", "Receiver") partial=True) msg_type = struct.unpack('! B', msg_type)[0] logger.debug("msg_type:%s", msg_type) # yield stream.read_bytes(4, partial=True) msg_len = struct.unpack('! I', msg_len)[0] logger. Debug ("msg_len:%s", msg_len) if msg_type == 1: # logger. Debug ("msg_len:%s", msg_len) if msg_type == 1: # logger. ) self.handle_text_stream(stream, sender, msg_len) elif msg_type == 2: logger.debug("picture message ..." ) self.handle_pic_stream(stream, sender, msg_len) except StreamClosedError: LOGGER. DEBUG ("%s is offline ", address) DEL ChatServer.clients[address] break @gen. Coroutine def handle_text_stream(self, self) Sender, sender, msg_len): "" Processor text data :param stream: :param send_to: :param msg_len: :return: """ data = yield stream.read_bytes(msg_len, partial=True) data = struct.unpack("!" + STR (msg_len)+"s", data) logger.debug("data:%s", data) try: # package data, data format: + data sender + data type + data length + data body binary_msg = struct. Pack ("! IBI" + str(msg_len) + "s", sender, 1, msg_len, Data [0]) # yield stream.write(binary_msg) logger.debug("="*25) except KeyError: Pass @gen. Coroutine def handle_pic_stream(self, stream, sender, msg_len): pass if __name__ == '__main__': sockets = bind_sockets(ChatServer.PORT) server = ChatServer() server.add_sockets(sockets) IOLoop.current().start()

The above is the specific code implementation, if there are mistakes, welcome to communicate with me to correct, thank you!