[經驗漫談]構建websocket伺服器和客戶端

2022-01-01 看我搞Python

    今天的內容不涉及算法,只講講如何使用tornado構建websocket服務。Python的web框架眾多,tornado在其中不如Django和Flask應用廣泛,也不如新出現的框架速度快,但是對我來說是最順手的,tornado功能上不複雜也不簡陋,性能也能完全滿足我的需求,是我十分鐘意的。

    tornado自帶websocket伺服器和客戶端的功能,可以拿來即用,十分方便。我曾經還使用過websockets這個包,本以為專門做websocket的工具會更強大一些,但是速度比較慢,不知道是我代碼的問題還是其他什麼原因。本文就簡單給出一個tornado實現的範例,供讀者參考。

    進入正題,直接上代碼


import jsonimport loggingimport signalfrom typing import Any, Dict, Union
import tornado.ioloopimport tornado.optionsimport tornado.webfrom tornado.concurrent import Futurefrom tornado.websocket import WebSocketHandler

class EchoWebSocket(WebSocketHandler): def write_message(self, message: Union[bytes, str, Dict[str, Any]], binary: bool = False) -> "Future[None]": if isinstance(message, (dict, )): message = json.dumps(message, ensure_ascii=False) return super().write_message(message, binary=binary)
def open(self): self.write_message({"msg": "WebSocket opened"})
def on_message(self, message): self.write_message({"msg": u"You said: " + message})
def on_close(self): logging.warning("WebSocket closed")
def check_origin(self, origin): return True

class MyApplication(tornado.web.Application): is_closing = False
def signal_handler(self, signum, frame): logging.info('exiting...') self.is_closing = True
def try_exit(self): if self.is_closing: tornado.ioloop.IOLoop.instance().stop() logging.info('exit success')

application = MyApplication([ (r"/", EchoWebSocket),])
if __name__ == "__main__": tornado.options.parse_command_line() signal.signal(signal.SIGINT, application.signal_handler) application.listen(8888) tornado.ioloop.PeriodicCallback(application.try_exit, 100).start() tornado.ioloop.IOLoop.instance().start()

    這部分是伺服器代碼。

17-22行覆寫了WebSocketHandler類的write_message方法,因為這裡使用json做服務端和客戶端之間通信的格式,如果通信內容帶中文等非ascii字符,可能會被處理成全部ascii字符,所以此處手動指定ensure_ascii=False。

33行這個check_origin方法,跟安全有關,此處直接返回True是為了演示方便,實際項目中不要這樣寫。如果你想要允許來自你站點子域名的連結的話,可以按照這個示例來寫:

def check_origin(self, origin):    parsed_origin = urllib.parse.urlparse(origin)    return parsed_origin.netloc.endswith(".mydomain.com")

    與服務端代碼配合的客戶端代碼如下:


import asyncioimport json
from tornado.websocket import websocket_connect

async def echo1(): conn = await websocket_connect("ws://127.0.0.1:8888") write_data = {"msg": "有錢大曬啊"} while True: await asyncio.sleep(1) conn.write_message(json.dumps(write_data, ensure_ascii=False)) msg = await conn.read_message() write_data = {"msg": "Sorry,有錢真系大曬嘅"} if msg is None: break print(json.loads(msg))

async def echo2(): def msg_callback(msg): print(msg)
conn = await websocket_connect("ws://127.0.0.1:8888", on_message_callback=msg_callback) write_data = {"msg": "有錢大曬啊"} while True: await asyncio.sleep(1) conn.write_message(json.dumps(write_data, ensure_ascii=False)) write_data = {"msg": "Sorry,有錢真系大曬嘅"}

if __name__ == "__main__": asyncio.run(echo2())

    代碼運行效果如下:

服務端

客戶端

    這裡的服務端和客戶端代碼組合起來是一個複讀機的功能,只為拋磚引玉,讀者可以魔改出一個有趣的東西。

    最後,感謝讀者能夠讀到這裡。

另一種websocket實現:GitHub - aaugustin/websockets: Library for building WebSocket servers and clients in Python

通過ctrl + c來關閉tornado的實現代碼:https://stackoverflow.com/questions/17101502/how-to-stop-the-tornado-web-server-with-ctrlc

相關焦點

  • C#實現WebSocket協議客戶端和伺服器Websocket-Sharp組件解析
    一.Websocket-sharp組件概述Websocket-sharp是一個C#實現websocket協議客戶端和服務端,websocket-sharp支持RFC 6455;WebSocket客戶端和伺服器;消息壓縮擴展;安全連接;HTTP身份驗證;查詢字符串,起始標題和Cookie;通過HTTP代理伺服器連接;.NET Framework
  • python 和 websocket 構建實時日誌跟蹤器
    前言websocket 是一種網絡傳輸協議。可在單個 TCP 連接上進行全雙工通信。基於此,websocket 使得客戶端與服務端的通信變得更加簡便和高效。什麼是 websocketwebsocket 是獨立的、創建在 TCP 上的協議。
  • Python進階:用websocket構建實時日誌跟蹤器
    前言websocket 是一種網絡傳輸協議。可在單個 TCP 連接上進行全雙工通信。基於此,websocket 使得客戶端與服務端的通信變得更加簡便和高效。什麼是 websocketwebsocket 是獨立的、創建在 TCP 上的協議。
  • 基於 Netty 搭建 WebSocket 集群實現伺服器消息推送
    這樣存在的缺點就是,一方面如果後端數據木有更新,那麼這一次http請求就是無用的,另一方面高並發情況下,短連結的頻繁創建銷毀,以及客戶端數量過大造成過多無用的http請求,都會對伺服器和帶寬造成壓力,短輪詢只適用於客戶端連接少,並發量不高的場景; (2)長輪詢:利用comet不斷向伺服器發起請求,伺服器將請求暫時掛起,直到有新的數據的時候才返回,相對短輪詢減少了請求次數得到了一定的優化
  • Django WebSocket Redis 在線聊天室
    通信請求只能由客戶端發起,服務端對請求做出應答處理弊端: HTTP 協議無法實現伺服器主動向客戶端發起消息。傳統模式下, Web 應用程式通過頻繁的 ajax 請求實現長輪詢( 輪詢是在特定的時間間隔(如每1秒),由瀏覽器對伺服器發出 HTTP 請求,然後由伺服器返回最新的數據給客戶端的瀏覽器)缺點:輪詢的效率低,非常浪費帶寬等資源(瀏覽器需要不斷的向伺服器發出請求)
  • 【經驗與坑】Spring Boot集成WebSocket
    1.2  技術簡介根據官網的介紹,WebSocket是一種網絡通信協議,那麼它到底和我們熟悉的HTTP協議有哪些不同呢?HTTP協議有一個缺陷:通信只能由客戶端發起。舉例說明:比如用戶想看天氣預報,這個過程只能是客戶端向服務端發出請求,伺服器返回查詢結果。
  • Springboot+websocket實現服務端、客戶端
    二、websocket介紹百度百科介紹:WebSokcet在公司實際使用websocket開發,一般來都是這樣的架構,首先websocket服務端是一個單獨的項目,其他需要通訊的項目都是以客戶端來連接,由服務端控制消息的發送方式(群發、指定發送)。
  • WebSocket
    下面我將使用nodejs搭建一個websocket伺服器,使用手機APP與該伺服器建立通訊。測試websocket即時通信。https://blog.csdn.net/qq_26942179/article/details/120486607?
  • 使用Go語言創建WebSocket服務
    第三部分實踐環節我們使用了gorilla/websocket庫幫助我們快速構建WebSocket服務,它幫封裝了使用Go標準庫實現WebSocket服務相關的基礎邏輯,讓我們能從繁瑣的底層代碼中解脫出來,根據業務需求快速構建WebSocket服務。WebSocket介紹WebSocket通信協議通過單個TCP連接提供全雙工通信通道。
  • Golang中用到的的Websocket庫
    開發者社區已經從 HTTP 長輪詢和 AJAX 走了很長一段路,終於找到了構建真正實時應用程式的解決方案。該解決方案以 WebSockets 的形式出現,它可以在用戶的瀏覽器和伺服器之間打開交互式會話。WebSockets 允許瀏覽器向伺服器發送消息並接收事件驅動的響應,而無需輪詢伺服器以獲取回復。
  • 探索 Golang 雲原生遊戲伺服器開發,根據官方示例實戰 Gorilla WebSocket 的用法
    示例分析這裡我整理下這個例子的官方 README.md一句話描述業務客戶端可以連接伺服器客戶端可以發送消息,然後服務端立即廣播消息技術描述業務本質上,就是對多個 websocket 連接的管理和讀寫操作。服務端向客戶端發送消息,技術上就是客戶端的 websocket 連接進行 讀 和 寫 操作。
  • 使用 Go 和 ReactJS 構建聊天系統(四):處理多客戶端
    本節完整代碼:GitHub[1]本文是關於使用 ReactJS 和 Go 構建聊天應用程式的系列文章的第 4 部分。你可以在這裡找到第 3 部分 - 前端實現[2]這節主要實現處理多個客戶端消息的功能,並將收到的消息廣播到每個連接的客戶端。
  • 一篇文章讀懂:WebSocket分析及實踐
    客戶端以一定的時間間隔向服務端發出請求,以頻繁請求的方式來保持客戶端和伺服器端的同步。這種同步方案的最大問題是:當客戶端以固定頻率向伺服器發起請求的時候,伺服器端的數據可能並沒有更新,這樣會帶來很多無謂的網絡傳輸,所以這是一種非常低效的實時方案。長輪詢:長輪詢是對定時輪詢的改進和提高,目地是為了降低無效的網絡傳輸。
  • 一文看懂:WebSocket分析及實踐
    客戶端以一定的時間間隔向服務端發出請求,以頻繁請求的方式來保持客戶端和伺服器端的同步。這種同步方案的最大問題是:當客戶端以固定頻率向伺服器發起請求的時候,伺服器端的數據可能並沒有更新,這樣會帶來很多無謂的網絡傳輸,所以這是一種非常低效的實時方案。長輪詢:長輪詢是對定時輪詢的改進和提高,目地是為了降低無效的網絡傳輸。
  • spring-boot之webSocket · 上
    它實現了瀏覽器與伺服器全雙工( full-duplex )通信一一允許伺服器主動發送信息給客戶端,這樣就可以實現從客戶端發送消息到伺服器 ,而伺服器又可以轉發消息到客戶端,這樣就能夠實現客戶端之間的交互。對於WebSocket的 開發 ,Spring也提供了 良好 的支持 。
  • Python連接websocket
    某些對於實時性要求高的web使用的不是再試ajax輪詢的方式來刷新數據,使用的是websocket,區別是
  • 伺服器推送之WebSocket--原理及Tomcat的實現
    現如今,許多場景下需要實現從服務端到客戶端的主動推送消息。
  • 一個最小的Python Websocket伺服器
    這段代碼建立了一個網頁到伺服器的雙向連結,網頁和伺服器可以相互發消息,每次發消息前不需要再次建立連結.如果用ajax來實現,我們需要使用很多奇技淫巧,來讓連結在消息發送完成後不被關掉.Websocket的出現大大加速了網頁和伺服器之間交換消息的速度.這裡我錄製了一個視頻,視頻中有兩個音頻播放器,這兩個播放器都是在網頁上,通過WebSocket連接到連接到音頻伺服器,從而間接地連接到spotify的音樂流服務.看,它們幾乎是同步的!
  • 【websocket】spring boot 集成 websocket 的四種方式
    比如你的啟動埠是 8080,而這個註解的值是 ws,那我們就可以通過 ws://127.0.0.1:8080/ws 來連接你的應用當 websocket 建立連接成功後會觸發這個註解修飾的方法,注意它有一個  Session 參數當 websocket 建立的連接斷開後會觸發這個註解修飾的方法,注意它有一個  Session 參數當客戶端發送消息到服務端時,會觸發這個註解修改的方法,它有一個 String
  • WebSocket 實戰
    傳統的請求-響應模式的 Web 開發在處理此類業務場景時,通常採用實時通訊方案,常見的是:輪詢,原理簡單易懂,就是客戶端通過一定的時間間隔以頻繁請求的方式向伺服器發送請求,來保持客戶端和伺服器端的數據同步。問題很明顯,當客戶端以固定頻率向伺服器端發送請求時,伺服器端的數據可能並沒有更新,帶來很多無謂請求,浪費帶寬,效率低下。