長輪詢javascript
在網頁,咱們常常掃碼登陸,結合以前的學習的知識點,來思考下,前端是如何知道用戶在手機上掃碼登陸了呢?css
長輪詢:html
客戶端不斷的向服務器發送請求前端
缺點:java
1. 開銷大 2. 浪費資源 3. 消耗流量jquery
websocket介紹web
長輪詢消耗太多資源,其中主要緣由是客戶端和服務端並無一直鏈接在一塊兒,若是可以讓客戶端和服務器一直保持鏈接呢?redis
正經介紹編程
WebSocket 協議是基於 TCP 的一種新的 HTML5 網絡協議。它實現了瀏覽器與服務器全雙工(full-duplex)通訊——容許服務器主動發送信息給客戶端。WebSocket通訊協議於2011年被IETF定爲標準RFC 6455,並被RFC7936所補充規範bootstrap
簡單說
客戶端和服務器一直鏈接在一塊兒
websocket 服務端編程
第一步:導入
from tornado.websocket import WebSocketHandler
第二步:基類
class BaseWebsocketHandler(WebSocketHandler,SessionMixin): def get_current_user(self): current_user = self.session.get('user_ID') if current_user: return current_user return None
第三步:跳轉 Handler
class IndexHandler(BaseHandler): @authenticated def get(self): self.render('08websocket.html')
第四步: websocket的Handler
class MessageHandler(BaseWebsocketHandler): ''' 創建鏈接 收發數據 斷開鏈接 ''' users = set() #當咱們的服務器想主動發送消息給瀏覽器的時候,調用write_message def open(self,*args,**kwargs): '''創建鏈接完成的代碼邏輯''' MessageHandler.users.add(self) #服務器要告訴每個客戶端有人上線 for i in self.users: # i.write_message('%s 上線了'%self.request.remote_ip) i.write_message('%s %s上線了'%(self.current_user,datetime.now())) def on_message(self, message): '''收發數據的代碼邏輯''' print(message) for i in self.users: i.write_message('%s -%s 說:%s'%(self.current_user,datetime.now(),message)) def on_close(self): '''斷開鏈接的代碼邏輯''' MessageHandler.users.remove(self) #服務器要告訴每個客戶端有人下線 for i in self.users: # i.write_message('%s 下線了'%self.request.remote_ip) i.write_message('%s %s下線了'%(self.current_user,datetime.now()))
展現結果以下:
07-websocket.py代碼以下:
import sys import time import tornado.web import tornado.ioloop import tornado.httpserver import tornado.options from tornado.web import RequestHandler,authenticated from tornado.options import define,options from pycket.session import SessionMixin from tornado.websocket import WebSocketHandler import util.ui_modules import util.ui_methods # import time from datetime import datetime from data.connect import session from data.user_modules import UserDetails, User define('port',default=8080,help='run server',type=int) class BaseHandler(RequestHandler,SessionMixin): '''聲明websocket基類''' def get_current_user(self): current_user = self.session.get('user_ID') if current_user: return current_user return None class BaseWebsocketHandler(WebSocketHandler,SessionMixin): def get_current_user(self): current_user = self.session.get('user_ID') if current_user: return current_user return None class IndexHandler(BaseHandler): @authenticated def get(self): self.render('08websocket.html') class LoginHandler(BaseHandler): def get(self): next_name = self.get_argument('next','') self.render('in_out.html',nextname=next_name) def post(self): '''驗證邏輯''' user = self.get_argument('name',None) password = self.get_argument('password',None) next_name = self.get_argument('next','') # print(next_name) # username = session.query(User).filter(User.username == user).first() username = User.get_name(user) # print(username) if username and password == username.password: #若是判斷用戶能夠登陸,咱們設置這樣一個加密的cookie進去 # self.set_secure_cookie('user_ID',user) self.session.set('user_ID',user) self.redirect(next_name) else: self.write('登陸失敗') class MessageHandler(BaseWebsocketHandler): ''' 創建鏈接 收發數據 斷開鏈接 ''' users = set() #當咱們的服務器想主動發送消息給瀏覽器的時候,調用write_message def open(self,*args,**kwargs): '''創建鏈接完成的代碼邏輯''' MessageHandler.users.add(self) #服務器要告訴每個客戶端有人上線 for i in self.users: # i.write_message('%s 上線了'%self.request.remote_ip) i.write_message('%s %s上線了'%(self.current_user,datetime.now())) def on_message(self, message): '''收發數據的代碼邏輯''' print(message) for i in self.users: i.write_message('%s -%s 說:%s'%(self.current_user,datetime.now(),message)) def on_close(self): '''斷開鏈接的代碼邏輯''' MessageHandler.users.remove(self) #服務器要告訴每個客戶端有人下線 for i in self.users: # i.write_message('%s 下線了'%self.request.remote_ip) i.write_message('%s %s下線了'%(self.current_user,datetime.now())) application = tornado.web.Application( handlers=[ (r'/index',IndexHandler), (r'/login',LoginHandler), (r'/websocket',MessageHandler), ], debug=True, template_path = 'templates', static_path='static', # autoescape = None, #全局取消轉義 ui_methods=util.ui_methods, ui_modules=util.ui_modules, cookie_secret ='qwe123', #cookie加鹽 login_url = '/login', pycket = { 'engine':'redis', 'storage':{ 'host':'localhost', 'port':6379, 'db_sessions':5, 'max_connections':2**10, }, 'cookies':{ 'expires_days':7 } } ) if __name__ == '__main__': tornado.options.parse_command_line() http_server = tornado.httpserver.HTTPServer(application) http_server.listen(options.port) tornado.ioloop.IOLoop.current().start()
webscoket 客戶端編程
服務器已經解決,那麼在客戶端該怎麼作呢?
WebSocket
WebSocket 是 HTML5 的標準之一,所以主流瀏覽器的 web 客戶端編程語言 Javascript 已經支持 WebSocket 的客戶端編程
初始化 WebSocket 對象
var socket = new WebSocket(url ):
處理函數
WebSocket.onopen : 此事件發生在 WebSocket 連接創建時
WebSocket.onmessage : 此事件發生在收到了來自服務器的消息時
WebSocket.onclose : 此事件發生在與服務器的連接關閉時
WebSocket.onerror : 此事件發生在通訊過程當中有任何錯誤時
主動操做函數
WebSocket.send(data) :向服務器發送消息
WebSocket.close() :主動關閉現有連接
08websocket.html代碼以下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title> WebSocket </title> <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.css" rel="stylesheet"> <style> *{ margin: 0; padding: 0; } .box{ width: 800px; margin-left: auto; margin-right: auto; margin-top: 25px; } #text{ width: 685px; height: 130px; border: 1px solid skyblue; border-radius: 10px; font-size: 20px; text-indent: 1em; resize:none; outline: none; } #text::placeholder{ color: skyblue; } .btn{ width: 100px; margin: -27px 0 0px 8px; } #messages{ padding-left: 10px; font-size: 25px; } #messages li{ list-style: none; color: #000; line-height: 30px; font-size: 18px; } </style> </head> <body> <div class="box"> <div> <textarea id="text" placeholder="請輸入您的內容"></textarea> <a href="javascript:WebSocketSend();" class="btn btn-primary">發送</a> </div> <ul id="messages"> </ul> </div> <script src="{{ static_url('js/jquery-2.2.0.min.js') }}"></script> <script type="text/javascript"> var mes = document.getElementById('messages'); if("WebSocket" in window){ mes.innerHTML = "發送WebSocket請求成功!"; var ws = new WebSocket("ws://127.0.0.1:8080/websocket"); ws.onopen = function () { alert('鏈接已打開請聊天') }; ws.onmessage = function (goudan) { var received_msg = goudan.data; var aLi = $("<li>"+received_msg+"</li>"); // $(mes).append($(aLi)) // 方法一 // $(aLi).appendTo(mes); // 方法二 $(mes).prepend($(aLi)) // 方法一 }; ws.onclose = function () { mes.innerHTML = mes.innerHTML + "<br>鏈接已經關閉..."; }; } else { mes.innerHTML = "發送WebSocket請求失敗!" } function WebSocketSend() { ws.send($("#text").val()); $("#text").val(""); } </script> </body> </html>