2019.7.15javascript
Http: 超文本傳輸協議 傳輸:Socket TCP 3次握手 斷開 四次揮手html
無狀態請求鏈接前端
TCP 3次握手 發起一次請求 - 一次響應 - 鏈接就斷開了java
http://www.baidu.com 長時間無請求時,不佔用任何資源jquery
劣勢:web
無狀態 - 好比 : 客戶端1向服務器發起請求 - 服務器確認客戶端1的身份 - 處理 - 響應 - 斷開 客戶端1向服務器發起請求 - 服務器確認客戶端1的身份 - 處理 - 響應 - 斷開
服務器主動向客戶端推送消息json
WeChat - 微信 ‘你’發送一條微信 - 給服務器 - ‘你好!’ - 服務器收到消息 - 服務器尋找 ‘我’ - 對着個人鏈接 (客戶端) - 發送 你好! WeChatPay AliPay
客戶端輪詢 - 由客戶端向服務器發起請求 每秒10次左右(QPS 每秒發起請求的次數限制)flask
場景模擬後端
傳達室 收發快遞模型 1.大爺(接收快遞) - 小二 半年以後 扔掉 2.大爺(接收快遞) - 小二 -小二從宿舍跑到傳達室 - 問大爺 有我快遞嗎? -大爺回答:你丫誰呀? 我是大三小二 - 我知道了,你找我什麼事兒? - 小二 : 有我快遞嗎? - 大爺:我給你找找,沒找着,你回去把,一會過來 - 小二 :大爺再見 再見 再見 再見 - 小二到宿舍想起來快遞沒拿 - 又去傳達室取快遞(重複上面的過程) - 不少個小二 同事問大爺快遞 知道好久之後 - 小二 我是大三的小二 - 我知道了,你彙總啊我什麼事兒? - 小二 : 有我快遞嗎? - 大爺: 我這兒真有你的快遞 - 小二 拿走快遞,飛奔二區 - 小二:大爺再見 再見 再見 再見
小資源訪問時 優點很明顯 - 由於客戶端較少瀏覽器
服務器長輪詢 - 服務器不響應客戶端而是將鏈接暫時保持住 5 秒以後 沒有消息,響應客戶端
必定時間以後 5s以後 斷開鏈接, 客戶端從新發起請求
情景模擬:
大爺(接收快遞) - 小二 傳達室裝修了 - 創建了一個茶室 - 服務升級了 小二到傳達室 - 問大爺有我快遞嗎? - 大爺: 你丫誰呀? - 小二:我是大三小二 - 大爺:我知道了,你找我什麼事兒? - 小二: 有我快遞嗎? - 大爺:進屋作作,屋裏有差,我給你找找快遞 - 小二喝茶中。。。。。。 - 大爺:你多等會 - 小二喝茶中。。。。。。 - 大爺:你多等會 - 小二喝茶中。。。。。。 - 小二: 大爺,我去趟廁所 - 斷開 - 小二上完廁所,不對呀,我又不是去喝茶的 - 小二來到傳達室 loop 小二到傳達室 - 問大爺有我快遞嗎? - 大爺: 你丫誰呀? - 小二:我是大三小二 - 大爺:我知道了,你找我什麼事兒? - 小二: 有我快遞嗎? - 大爺:進屋作作,屋裏有差,我給你找找快遞 - 小二喝茶中。。。。。。 - 大爺說 找到了,你的快遞 - 小二拿着快遞美美的回去了 斷開了
優點:
小二不用那麼累了 客戶端不用大量QPS
劣勢:
傳達室的茶室空間 嚴重浪費服務器資源
大爺學會了影分身 開啓多線程服務客戶端
鏈接保持 - Http 發起請求在請求中寫一個協議 - WebSocket - 收到請求,自動保持此鏈接 - 永久不斷開, 除非主動斷開 - 能夠經過此鏈接主動找到客戶端
場景模擬
大爺(接收快遞) - 小二 傳達室進入信息化時代,裝電話了 2萬臺電話 小二到傳達室 - 問大爺有我快遞嗎? - 大爺: 你丫誰呀? - 小二:我是大三小二 - 大爺:我知道了,你找我什麼事兒? - 小二: 有我快遞嗎? - 大爺:你把電話號碼留下,回去等我電話,接了以後別掛 - 小二回到宿舍證號聽見大爺來電話了 - 小二接電話 , 對面,我是你大爺,電話別掛,隨時聽着,有快遞就過來取 - 保持通話
優點:數據實時性
劣勢:服務器和客戶端須要一個線程來等待消息
玩遊戲:一個服務器有資源限制,因此分區,不少個服務器
服務器 完成 IO多路複用
2 . GeventWebsocket + Flask
Web (Http) + Socket (鏈接保持)
Flask中運行WebSocket - GeventWebsocket
wsgi ---> envir ---> view
wsgi ---> http ---> envir ---> view
wsgi ---> websockethandler ---> envir ---> view
websockethandler 監聽了 請求頭中的?
{'GATEWAY_INTERFACE': 'CGI/1.1', 'SERVER_SOFTWARE': 'gevent/1.4 Python/3.6', 'SCRIPT_NAME': '', 'wsgi.version': (1, 0), 'wsgi.multithread': False, 'wsgi.multiprocess': False, 'wsgi.run_once': False, 'wsgi.url_scheme': 'http', 'wsgi.errors': <_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>, 'SERVER_NAME': 'Win7-2019WPWAAA', 'SERVER_PORT': '9537', 'REQUEST_METHOD': 'GET', 'PATH_INFO': '/my_socket', 'QUERY_STRING': '', 'SERVER_PROTOCOL': 'HTTP/1.1', 'REMOTE_ADDR': '127.0.0.1', 'REMOTE_PORT': '50844', 'HTTP_HOST': '127.0.0.1:9537', 'HTTP_CONNECTION': 'Upgrade', 'HTTP_PRAGMA': 'no-cache', 'HTTP_CACHE_CONTROL': 'no-cache', 'HTTP_USER_AGENT': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36', 'HTTP_UPGRADE': 'websocket', 'HTTP_ORIGIN': 'http://localhost:49419', 'HTTP_SEC_WEBSOCKET_VERSION': '13', 'HTTP_ACCEPT_ENCODING': 'gzip, deflate, br', 'HTTP_ACCEPT_LANGUAGE': 'zh-CN,zh;q=0.9', 'HTTP_COOKIE': 'csrftoken=5L4cgBIxsjanDPXGuTBlOk5ihhrn8LYnSppNIG4LyEclJHsC6MOC7AR9K1jbDJUO; sessionid=ofv3e4j3kmwo26wrimax68wz5t56rmr3', 'HTTP_SEC_WEBSOCKET_KEY': 'KNmnx/BwHQ1R3Q+DxJNRGQ==', 'HTTP_SEC_WEBSOCKET_EXTENSIONS': 'permessage-deflate; client_max_window_bits', 'wsgi.input': <gevent.pywsgi.Input object at 0x0000000003C85A08>, 'wsgi.input_terminated': True, 'wsgi.websocket_version': '13', 'wsgi.websocket': <geventwebsocket.websocket.WebSocket object at 0x0000000003CB60B0>, 'werkzeug.request': <Request 'http://127.0.0.1:9537/my_socket' [GET]>}
'wsgi.websocket': <geventwebsocket.websocket.WebSocket object at 0x0000000003CB60B0>,
#{'GATEWAY_INTERFACE': 'CGI/1.1', 'SERVER_SOFTWARE': 'gevent/1.4 Python/3.6', 'SCRIPT_NAME': '', 'wsgi.version': (1, 0), 'wsgi.multithread': False, 'wsgi.multiprocess': False, 'wsgi.run_once': False, 'wsgi.url_scheme': 'http', 'wsgi.errors': <_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>, 'SERVER_NAME': 'Win7-2019WPWAAA', 'SERVER_PORT': '9537', 'REQUEST_METHOD': 'GET', 'PATH_INFO': '/my_socket', 'QUERY_STRING': '', 'SERVER_PROTOCOL': 'HTTP/1.1', 'REMOTE_ADDR': '127.0.0.1', 'REMOTE_PORT': '50450', 'HTTP_HOST': '127.0.0.1:9537', 'HTTP_CONNECTION': 'keep-alive', 'HTTP_CACHE_CONTROL': 'max-age=0', 'HTTP_UPGRADE_INSECURE_REQUESTS': '1', 'HTTP_USER_AGENT': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36', 'HTTP_ACCEPT': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3', 'HTTP_ACCEPT_ENCODING': 'gzip, deflate, br', 'HTTP_ACCEPT_LANGUAGE': 'zh-CN,zh;q=0.9', 'HTTP_COOKIE': 'csrftoken=5L4cgBIxsjanDPXGuTBlOk5ihhrn8LYnSppNIG4LyEclJHsC6MOC7AR9K1jbDJUO; sessionid=ofv3e4j3kmwo26wrimax68wz5t56rmr3', 'wsgi.input': <gevent.pywsgi.Input object at 0x0000000003A65A08>, 'wsgi.input_terminated': True, 'werkzeug.request': <Request 'http://127.0.0.1:9537/my_socket' [GET]>}
Host: 127.0.0.1:9537 Connection: keep-alive Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3 Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 Cookie: csrftoken=5L4cgBIxsjanDPXGuTBlOk5ihhrn8LYnSppNIG4LyEclJHsC6MOC7AR9K1jbDJUO
ws
WebSocket {url: "ws://127.0.0.1:9537/my_socket", readyState: 3, bufferedAmount: 0, onopen: null, onerror: null, …}
Host: 127.0.0.1:9537 Connection: Upgrade Pragma: no-cache Cache-Control: no-cache User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36 Upgrade: websocket # == websocket 請求 websockethandler處理的key 握手的信息 Origin: http://localhost:49419 Sec-Websocket-Version: 13 # Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 Cookie: csrftoken=5L4cgBIxsjanDPXGuTBlOk5ihhrn8LYnSppNIG4LyEclJHsC6MOC7AR9K1jbDJUO; sessionid=ofv3e4j3kmwo26wrimax68wz5t56rmr3 Sec-Websocket-Key: jiytsu3cA3JWnElexaajjA== # 公鑰 Sec-Websocket-Extensions: permessage-deflate; client_max_window_bits
和一個東西計算出私鑰 , 匹配出來的值能不能創建起聯繫
html 代碼:
<script type="application/javascript">
ws = new WebSocket('ws://127.0.0.1:9537/my_socket');
WebSocket {url: "ws://127.0.0.1:9537/my_socket", readyState: 0, bufferedAmount: 0, onopen: null, onerror: null, …}
ws
WebSocket {url: "ws://127.0.0.1:9537/my_socket", readyState: 1, bufferedAmount: 0, onopen: null, onerror: null, …}
0 鏈接沒有創建好
1 創建好了 保持鏈接
2 客戶端主動斷開 (由於是客戶端的,看不出來,不是服務器發的)
3 服務器主動斷開鏈接 (1次就斷開)
VM258:1 WebSocket is already in CLOSING or CLOSED state.
<script type="application/javascript"> var ws = new WebSocket('ws/127.0.0.1:9537/my_socket')
http_serv = WSGIServer(('0.0.0.0',9537),app,handler_class=WebSocketHandler) #WSH 如何處理ws請求的
websocket 快速實現功能
要實現大的功能1G : 用底層
想法:
jquery
微信頁面(微信我的資料)
加上js?
多併發
ql
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>羣聊</title> </head> <body> <p><input type="text" id="content"><button onclick="send_msg()">發送</button></p> <div id="chat_list"> </div> </body> <script type="application/javascript"> var ws = new WebSocket("ws://192.168.16.40:9527/my_socket"); // 監聽電話 ws.onmessage = function (eventMessage) { console.log(eventMessage.data); var p = document.createElement("p"); p.innerText = eventMessage.data; document.getElementById("chat_list").appendChild(p); }; function send_msg() { var content = document.getElementById("content").value; ws.send(content); }; </script> </html>
py
# 客戶端 # 服務端 # Http Flask 瀏覽器 # Websocket GeventWebsocket+Flask 客戶端JavaScript(Websocket客戶端) from flask import Flask,request,render_template from geventwebsocket.handler import WebSocketHandler # 提供WS協議處理 from geventwebsocket.server import WSGIServer # 承載服務 from geventwebsocket.websocket import WebSocket # 語法提示 app = Flask(__name__) user_socket_list = [] @app.route("/my_socket") def my_socket(): # 獲取當前客戶端與服務器的Socket鏈接 user_socket = request.environ.get("wsgi.websocket") # type:WebSocket if user_socket: user_socket_list.append(user_socket) print(len(user_socket_list),user_socket_list) # print(user_socket,"OK 鏈接已經創建好了,接下來發消息吧") while 1: msg = user_socket.receive() print(msg) for usocket in user_socket_list: try: usocket.send(msg) except: continue # user_socket.send(msg) # print(request.headers) @app.route("/gc") def gc(): return render_template("gc.html") if __name__ == '__main__': # app.run("0.0.0.0",9527) http_serv = WSGIServer(("0.0.0.0",9527),app,handler_class=WebSocketHandler) http_serv.serve_forever()
sl.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>羣聊</title> </head> <body> <p>個人暱稱:<input type="text" id="username"> <button onclick="loginGc()">登陸</button> </p> <p>給<input type="text" id="to_user">發送<input type="text" id="content"> <button onclick="send_msg()">發送</button> </p> <div id="chat_list"> </div> </body> <script type="application/javascript"> var ws = null; function loginGc() { var username = document.getElementById("username").value; ws = new WebSocket("ws://192.168.16.40:9527/my_socket/" + username); // 監聽電話 ws.onmessage = function (eventMessage) { console.log(eventMessage.data); str_obj = JSON.parse(eventMessage.data); var p = document.createElement("p"); p.innerText = str_obj.from_user +" : "+str_obj.chat; document.getElementById("chat_list").appendChild(p); }; }; function send_msg() { var username = document.getElementById("username").value; var to_user = document.getElementById("to_user").value; var content = document.getElementById("content").value; var sendStr = { from_user:username, to_user:to_user, chat:content }; ws.send(JSON.stringify(sendStr)); }; </script> </html>
py
# 客戶端 # 服務端 # Http Flask 瀏覽器 # Websocket GeventWebsocket+Flask 客戶端JavaScript(Websocket客戶端) import json from flask import Flask,request,render_template from geventwebsocket.handler import WebSocketHandler # 提供WS協議處理 from geventwebsocket.server import WSGIServer # 承載服務 from geventwebsocket.websocket import WebSocket # 語法提示 app = Flask(__name__) # user_socket_dict = {nicheng:lianjie} user_socket_dict = {} @app.route("/my_socket/<username>") def my_socket(username): # 獲取當前客戶端與服務器的Socket鏈接 user_socket = request.environ.get("wsgi.websocket") # type:WebSocket if user_socket: user_socket_dict[username] = user_socket print(len(user_socket_dict),user_socket_dict) # print(user_socket,"OK 鏈接已經創建好了,接下來發消息吧") while 1: msg = user_socket.receive() msg_dict = json.loads(msg) # msg = user_socket.receive() to_user_nick = msg_dict.get("to_user") print(to_user_nick) to_user_socket = user_socket_dict.get(to_user_nick) to_user_socket.send(msg) @app.route("/sl") def sl(): return render_template("sl.html") if __name__ == '__main__': # app.run("0.0.0.0",9527) http_serv = WSGIServer(("0.0.0.0",9527),app,handler_class=WebSocketHandler) http_serv.serve_forever()
ws = new WebSocket('ws://192.168.16.40:9537/gc'); WebSocket is already in CLOSING or CLOSED state.
錯誤 2
ws = new WebSocket('ws://192.168.16.40:9537/my_socket');
WebSocket {url: "ws://192.168.16.40:9537/my_socket", readyState: 0, bufferedAmount: 0, onopen: null, onerror: null, …} VM65:1 WebSocket connection to 'ws://192.168.16.40:9537/my_socket' failed: Error in connection establishment:
發錯了地址,發到了 40端口,老師的端口了
gc.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p><input type="text" id="content"><button onclick="send_msg()">發送</button></p> <div id="chat_list"> </div> </body> <script type="application/javascript"> // // 監聽電話 var ws = new WebSocket('ws://127.0.0.1:9537/my_socket'); ws.onmessage = function (eventMessage) { console.log(eventMessage.data); var p = document.createElement('p'); p.innerText = eventMessage.data; document.getElementById('chat_list').appendChild(p); }; function send_msg() { var content = document.getElementById('content').value; ws.send(content); } </script> </html>
老 gc .html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <!--放聊天記錄--> <p>個人暱稱:<input type="text" id="username"><button onclick="loginGc()">登錄</button></p> <p><input type="text" id="content"> <button onclick="send_msg()">發送</button></p> <div id="chat_list"> </div> <script type="application/javascript"> var ws = null; // // 監聽電話 // ws.onmessage = function (eventMessage) { // console.log(eventMessage.data); // var p = document.createElement('p'); // p.innerText = eventMessage.data; // document.getElementById('chat_list').appendChild(p); // }; function loginGc() { var username = document.getElementById('username').value; var ws = new WebSocket('ws://127.0.0.1:9537/my_socket/'); ws.send(content); ws.onmessage = function (eventMessage) { console.log(eventMessage.data); var p = document.createElement('p'); p.innerText = eventMessage.data; document.getElementById('chat_list').appendChild(p); }; } function send_msg() { var content = document.getElementById('content').value; var username = document.getElementById('username').value; var ws = new WebSocket('ws://127.0.0.1:9537/my_socket/'); var sendStr = { from_user : username, chat : content }; ws.send(content); } </script> </body> </html>
ws.onmessage = function (eventMessage) {
eventMessage : 和request似的?
函數做用?
function send_msg() { var content = document.getElementById("content").value; ws.send(content); }
Uncaught ReferenceError: send_msg is not defined
var ws = new WebSocket("ws://192.168.16.90:9537/my_socket"); // 監聽電話 ws.onmessage = function (eventMessage) { console.log(eventMessage.data); var p = document.createElement("p"); p.innerText = eventMessage.data; document.getElementById("chat_list").appendChild(p); };
沒有發送函數也能夠實現增長信息,只不過服務器端不顯示
<p><input type="text" id="content"><button onclick="send_msg()">發送</button></p>
並非,好像是沒有數據了? 這樣 數據是發過去又發回來的,爲何不直接使用呢
for usocket in user_socket_list: try: usocket.send(msg) #前端接收的eventmesaage.data 就是這個msg # print('haole') except: continue
也不知道改動的什麼地方,莫名其妙就行了
由於看不出那裏有錯,照抄的老師的,還把前端後端都換成老師的,而後去看視頻,發現老師是沒放在羣聊的文件夾裏,因此就把他提了出來,就好使了,而後再去運行以前的,也好使了。不知道錯誤在哪?還會出錯的,對嗎?
告訴你:
不是 from flask import Flask,request,render_template
而是 import json 腦子怎麼長的?奇特!
前端寫 JSON 大寫 額
ws.send(JSON.stringify(sendStr));
laoqunliao
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <!--放聊天記錄--> <p>個人暱稱:<input type="text" id="username"><button onclick="loginGc()">登錄</button></p> <p><input type="text" id="content"> <button onclick="send_msg()">發送</button></p> <div id="chat_list"> </div> </body> <script type="application/javascript"> var ws = null; function loginGc() { var username = document.getElementById('username').value; ws = new WebSocket('ws://192.168.16.90:9537/my_socket/'+username); ws.onmessage = function (eventMessage) { console.log(eventMessage.data); var p = document.createElement('p'); p.innerText = eventMessage.data; document.getElementById('chat_list').appendChild(p); }; } function send_msg() { var content = document.getElementById('content').value; var username = document.getElementById('username').value; var sendStr = { from_user : username, chat : content }; ws.send(JSON.stringify(sendStr)); }; </script> </html>
str_obj = JSON.parse(eventMessage.data); p.innerText = str_obj.from_user +" : "+str_obj.chat;
顯示 ----> dasf : adfas
p.innerText = eventMessage.data;
顯示 ----> {"from_user":"adas","chat":"ada"}
這個函數果真沒大有實際做用,由於經過直接打開html , 錯誤由於無法識別 tmplates 嗎?
# @app.route("/gcs") # def gc(): # return render_template("gcs.html")
那個make jinja 了 哪一個能夠被識別好像 那就能夠藍圖文件夾用公有資源了把?!
ws.send(JSON.stringify(sendStr));
是我沒點登錄 ? 發的是空
Uncaught TypeError: Cannot read property 'send' of null
AttributeError: 'NoneType' object has no attribute 'send' # kong不能打.send
Cannot read property 'send' of null
是由於沒有用戶,不支持離線。亮哥說。解決了,好似,可是我以前怎麼可已發過去?也沒有確認用戶存在因此接收功能吧?
多我的聊天,因此須要另一我的,不能本身和本身聊吧
錯誤返回:
null not revice()
websockethandler 也是 WSGI的 只不過封裝了
繼承的WSGIHandler 除了可以處理標準的http,還能夠處理webserver
self.environ.update ({'wsgi.websocket':None}) #http仍是web都有environ原始信息
self.websocket = None #都給了None
只有websocket 纔有http_update , http請求沒有
讀源碼的時候各類記筆記: 防止忘了 #
ws登陸 ws://192.168.16.90 登陸 aaa sec 密鑰 。。。
self.websocket = Websocket(self.environ,) #夯住了 新的長鏈接一直保持着
http -> websocket
environ.update = {''} # http請求進來 沒有http-upgrate 只有None , None無法receive
明天講websocket 握手原理 和 加密 (有時間的話)
SUPPORTED_VERSIONS = ('13', '8', '7') GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
self.environ.update({ 'wsgi.websocket': None }) self.websocket = None
upgrade = self.environ.get('HTTP_UPGRADE', '').lower()
'HTTP_UPGRADE': 'websocket'
if upgrade == 'websocket': connection = self.environ.get('HTTP_CONNECTION', '').lower() #加到了connection裏面
'HTTP_CONNECTION': 'Upgrade' ws都有 這兩個key
if 'upgrade' not in connection: # This is not a websocket request, so we must not handle it self.logger.warning("Client didn't ask for a connection " "upgrade") return else: # This is not a websocket request, so we must not handle it return
if self.request_version != 'HTTP/1.1': # websocket 默認是http/1.1 略過
'HTTP_SEC_WEBSOCKET_VERSION': '13', #
if self.environ.get('HTTP_SEC_WEBSOCKET_VERSION'): return self.upgrade_connection()
def upgrade_connection(self):
version = self.environ.get("HTTP_SEC_WEBSOCKET_VERSION")
SUPPORTED_VERSIONS = ('13', '8', '7')
爲Sec-WebSocket-Accept 作準備
key = self.environ.get("HTTP_SEC_WEBSOCKET_KEY", '').strip()
key_len = len(base64.b64decode(key))
http 請求不就是tcp請求,tcp請求本質上不就是socket請求,因此把 def upgrade_connection(self):
#Validate and 'upgrade' the HTTP request to a WebSocket request. ---> self.websocket
若是Sec-WebSocket-Accept匹配對了,一直保持着
self.websocket = WebSocket(self.environ, Stream(self), self) #建立一個新的鏈接 保持長鏈接 # 裏面是init函數 self.environ.update({ 'wsgi.websocket_version': version, 'wsgi.websocket': self.websocket #把鏈接放到wsig裏了 })
class WebSocket(object): def __init__(self, environ, stream, handler): #self == WSGIServer? ?WebSocketHandler
if PY3: accept = base64.b64encode( #accept驗證經過的字符串 hashlib.sha1((key + self.GUID).encode("latin-1")).digest() ).decode("latin-1") #經過以後才能一直鏈接 else: accept = base64.b64encode(hashlib.sha1(key + self.GUID).digest())
headers = [ ("Upgrade", "websocket"), ("Connection", "Upgrade"), ("Sec-WebSocket-Accept", accept) ]
走了這麼多,給http請求的返回了none,給ws請求的返回了 websocket(不知道是什麼)
http請求,源碼裏,wsgi.websocket 給的none 而後就返回了
user_socket = request.environ.get("wsgi.websocket") # type:WebSocket if user_socket: user_socket_list.append(user_socket) print(len(user_socket_list),user_socket_list) # print(user_socket,"OK 鏈接已經創建好了,接下來發消息吧") while 1: msg = user_socket.receive() # send_msg 發過來的信息 # http請求這裏是None , print(msg)
因此,AttributeError: 'NoneType' object has no attribute 'receive'
from flask import Flask,request,render_template from geventwebsocket.handler import WebSocketHandler #提供WS協議 from geventwebsocket.server import WSGIServer #承載服務 from geventwebsocket.websocket import WebSocket # 語法提示 app = Flask(__name__) user_socket_list = [] #存放每一個socket的列表 @app.route('/ql') def ql(): return render_template('ql1.html') @app.route('/my_socket') def my_socket(): # 獲取當前客戶端與服務器的socket鏈接 user_socket = request.environ.get('wsgi.websocket') #type:WebSocket if user_socket: user_socket_list.append(user_socket) # 加入多個用戶 print(len(user_socket_list),user_socket_list) #1 [<geventwebsocket.websocket.WebSocket object at 0x0000000003CB90B0>] while 1 : msg = user_socket.receive() # 接收前端發過來的信息 print(msg) for usocket in user_socket_list: try: usocket.send(msg) except : continue #斷開鏈接的 不影響整個羣聊 if __name__ == '__main__': http_serv = WSGIServer(('0.0.0.0',9527),app,handler_class=WebSocketHandler) http_serv.serve_forever()
</head> <body> <p><input type="text" id="content"> <button onclick="send_msg()">發送</button></p> <div id="chat_list"> </div> </body> <script type="application/javascript"> // 爲何? application 格式的? // 做用 添加聊天信息在chat_list那 var ws = new WebSocket('ws://192.168.16.90:9527/my_socket'); // 監聽電話 ws.onmessage = function (eventMessage) { // eventMessage 存放信息 console.log(eventMessage.data); // document 方法? var p = document.createElement('p'); // 建立p標籤 p.innerText = eventMessage.data; // 數據寫入p data是前面後端傳過來的 document.getElementById('chat_list').appendChild(p); // 加入到前面列表 }; function send_msg(){ // 做用 , 發給後端,而且激活 onmessage var content = document.getElementById('content').value; ws.send(content); }; </script>
<p>個人暱稱:<input type="text" id="username"><button onclick="loginGc()">登錄</button></p> <p><input type="text" id="content"> <button onclick="send_msg()">發送</button></p> <div id="chat_list"> </div> </body> <script type="application/javascript"> var ws = null; function loginGc() { var username = document.getElementById('username').value; ws = new WebSocket('ws://192.168.16.90:9537/my_socket/'+username); ws.onmessage = function (eventMessage) { console.log(eventMessage.data); str_obj = JSON.parse(eventMessage.data); var p = document.createElement('p'); p.innerText = str_obj.from_user +" : "+str_obj.chat; document.getElementById('chat_list').appendChild(p); }; } function send_msg() { var content = document.getElementById('content').value; var username = document.getElementById('username').value; var sendStr = { from_user : username, chat : content }; ws.send(JSON.stringify(sendStr)); }; </script>
import json user_socket_dict = {} @app.route("/my_socket/<username>") def my_socket(username): # 獲取當前客戶端與服務器的Socket鏈接 user_socket = request.environ.get("wsgi.websocket") # type:WebSocket if user_socket: user_socket_dict[username] = user_socket print(len(user_socket_dict),user_socket_dict) # print(user_socket,"OK 鏈接已經創建好了,接下來發消息吧") while 1: # msg = json.loads(user_socket.receive()) msg = user_socket.receive() print(msg) for usocket in user_socket_dict.values(): print(usocket) try: usocket.send(msg) except: continue
<p>個人暱稱:<input type="text" id="username"> <button onclick="loginGc()">登陸</button> </p> <p>給<input type="text" id="to_user">發送<input type="text" id="content"> <button onclick="send_msg()">發送</button> </p> <div id="chat_list"> </div> </body> <script type="application/javascript"> var ws = null; function loginGc() { var username = document.getElementById("username").value; ws = new WebSocket("ws://192.168.16.90:9537/my_socket/" + username); // 監聽電話 ws.onmessage = function (eventMessage) { console.log(eventMessage.data); str_obj = JSON.parse(eventMessage.data); var p = document.createElement("p"); p.innerText = str_obj.from_user +" : "+str_obj.chat; document.getElementById("chat_list").appendChild(p); }; }; function send_msg() { var username = document.getElementById("username").value; var to_user = document.getElementById("to_user").value; var content = document.getElementById("content").value; var sendStr = { from_user:username, to_user:to_user, chat:content }; ws.send(JSON.stringify(sendStr)); }; </script>
app = Flask(__name__) # user_socket_dict = {nicheng:lianjie} user_socket_dict = {} @app.route("/my_socket/<username>") def my_socket(username): # 獲取當前客戶端與服務器的Socket鏈接 user_socket = request.environ.get("wsgi.websocket") # type:WebSocket if user_socket: user_socket_dict[username] = user_socket # bbbb = {gevent print(len(user_socket_dict),'dict',user_socket_dict) # print(user_socket,"OK 鏈接已經創建好了,接下來發消息吧") while 1: msg = user_socket.receive() msg_dict = json.loads(msg) # msg = user_socket.receive() to_user_nick = msg_dict.get("to_user") #'bbbb' print('toueser-nick',to_user_nick) to_user_socket = user_socket_dict.get(to_user_nick) #'bbbb' to_user_socket.send(msg) @app.route("/sl") def sl(): return render_template("sl.html")