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")