摘要:本文主要介紹了在框架中使用實現簡單服務器的過程。在網絡通信中,需要發送二進制流數據函數負責數據組包,即將數據按照規定的傳輸協議組合起來函數負責數據拆包,即按照規定的協議將數據拆分開來。不多說,具體實現代碼咱們來看一下。
本文主要介紹了在tornado框架中,使用tcpserver,tcpclient,struct.pack(),struct.unpack實現簡單echo服務器的過程。
在網絡通信中,需要發送二進制流數據;struct.pack()函數負責數據組包,即將數據按照規定的傳輸協議組合起來;struct.unpack()函數負責數據拆包,即按照規定的協議將數據拆分開來。
不多說,具體實現代碼咱們來看一下。
tcp客戶端代碼如下:
# coding=utf-8 import struct import logging from tornado import ioloop, gen from tornado.tcpclient import TCPClient """ tcpclient-struct.pack()組包 發送數據包格式:消息頭+消息體 消息頭:消息發送者(4字節)+消息接收者(4字節)+消息類型(1字節)+消息體中數據長度(4字節) 消息體:待發送數據 struct.unpack()拆包 接收數據包格式:消息頭+消息體 消息頭:消息發送者(4字節)+消息類型(1字節)+消息體中數據長度(4字節) 消息體:待接收數據 """ 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("輸入:") bytes_msg = bytes(msg.encode("utf-8")) # 消息發送者 chat_id = 10000000 # 消息接收者 receive_id = 10000001 # 消息類型 1-文本 2-圖片 3-語音 4-視頻 等 msg_type = 1 binary_msg = struct.pack("!IIBI"+str(len(msg))+"s", chat_id, receive_id, msg_type, len(msg), bytes_msg) # 發送數據 yield self.stream.write(binary_msg) @gen.coroutine def receive_message(self): """ 接收數據 :return: """ try: logger.debug("receive data ...") # 消息發送者 4字節 sender = yield self.stream.read_bytes(4, partial=True) sender = struct.unpack("!I", sender)[0] logger.debug("sender:%s", sender) # 消息類型 1字節 msg_type = yield self.stream.read_bytes(1, partial=True) msg_type = struct.unpack("!B", msg_type)[0] logger.debug("msg_type:%s", msg_type) # 消息長度 4字節 msg_len = yield self.stream.read_bytes(4, partial=True) msg_len = struct.unpack("!I", msg_len)[0] logger.debug("msg_len:%s", msg_len) # 真實數據 data = 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("127.0.0.1", 8888) c1.start() ioloop.IOLoop.instance().start() if __name__ == "__main__": main()
tcp服務端代碼:
# 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 """ tcpserver-struct.unpack()拆包 接收數據包格式:消息頭+消息體 消息頭:消息發送者(4字節)+消息接收者(4字節)+消息類型(1字節)+消息體中數據長度(4字節) 消息體:待接收數據 struct.pack()組包 轉發數據包格式:消息頭+消息體 消息頭:消息發送者(4字節)+消息類型(1字節)+消息體中數據長度(4字節) 消息體:待發送數據 """ 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 stream: :param address: :return: """ logger.debug("%s已上線", address) ChatServer.clients[address] = stream while True: try: # !表示使用大端方式解析數據 # 消息發送者 4字節 sender = yield stream.read_bytes(4, partial=True) sender = struct.unpack("!I", sender)[0] logger.debug("sender:%s", sender) # 消息接收者 4字節 receiver = yield stream.read_bytes(4, partial=True) receiver = struct.unpack("!I", receiver)[0] logger.debug("receiver:%s", receiver) # 消息類型 1字節 msg_type = yield stream.read_bytes(1, partial=True) msg_type = struct.unpack("!B", msg_type)[0] logger.debug("msg_type:%s", msg_type) # 消息長度 4字節 msg_len = 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("text message ...") 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已下線", address) del ChatServer.clients[address] break @gen.coroutine def handle_text_stream(self, stream, sender, msg_len): """ 處理文本數據 :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: # 打包數據,數據格式:數據發送者+數據類型+數據長度+數據體 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()
以上就是具體的代碼實現,如有錯誤,歡迎大家與我交流指正,謝謝!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/44741.html
摘要:中常用的幾個框架有等,今天來總結一下和的不同。本文使用的環境是。文件可以加載路由信息和項目配置信息,文件負責啟動項目。以上就簡單的比較了和幾個方面的不同,它們各有優缺點,實際工作中可以根據不同的需求選擇不同的框架進行開發。 python中常用的幾個web框架有django, tornado, flask等,今天來總結一下django和tornado的不同。工作中django和torna...
摘要:網絡編程網絡編程有常見的鏈接面向連接的,就像打電話必須要一來一往的做出回應是不面向鏈接的,不需要做出回應這是一個簡單的代碼例子輸入你的信息編程這是客戶端發送的信息 網絡編程 2017-07-12 18:51:50 bloggithub網絡編程有常見的tcp,udp 鏈接 tcp 面向連接的,就像打電話必須要一來一往的做出回應 udp 是不面向鏈接的, 不需要做出回應 這是一個簡單的tc...
摘要:前言本文將嘗試詳細的帶大家一步步走完一個異步操作從而了解是如何實現異步的其實本文是對上一篇文的實踐和復習主旨在于關注異步的實現所以會忽略掉代碼中的一些異常處理文字較多湊合下吧接下來只會貼出部分源碼幫助理解希望有耐心的同學打開源碼一起跟蹤一遍 前言 本文將嘗試詳細的帶大家一步步走完一個異步操作,從而了解tornado是如何實現異步io的. 其實本文是對[上一篇文][1]的實踐和復習 主...
摘要:應用層主要負責應用程序的協議,例如協議協議等。在計算機中,不同的應用程序是通過端口號區分的。區別在于,中只有發送端和接收端,不區分客戶端與服務器端,計算機之間可以任意地發送數據。 01網絡模型 *A:網絡模型 TCP/IP協議中的四層分別是應用層、傳輸層、網絡層和鏈路層,每層分別負責不同的通信功能,接下來針對這四層進行詳細地講解。 鏈路層:鏈路層是用于定義物理傳輸通道,通常是對...
摘要:譯者說于年月日發布,該版本正式支持的關鍵字,并且用舊版本編譯同樣可以使用這兩個關鍵字,這無疑是一種進步。原諒我沒排好版非阻塞非阻塞,單線程。其舊名稱仍作為一個別名。非阻塞,單線程。要使可以服務于加密的流量,需要把參數設置為一個對象。 譯者說 Tornado 4.3于2015年11月6日發布,該版本正式支持Python3.5的async/await關鍵字,并且用舊版本CPython編譯T...
閱讀 2184·2023-04-25 15:00
閱讀 2363·2021-11-18 13:14
閱讀 1192·2021-11-15 11:37
閱讀 3100·2021-09-24 13:55
閱讀 1237·2019-08-30 15:52
閱讀 2657·2019-08-29 12:35
閱讀 3373·2019-08-29 11:04
閱讀 1220·2019-08-26 12:13