2019.7.15
Http协议
Http: 超文本传输协议 传输:Socket TCP 3次握手 断开 四次挥手
无状态请求连接
TCP 3次握手 发起一次请求 - 一次响应 - 连接就断开了
http://www.baidu.com 长时间无请求时,不占用任何资源
劣势:
无状态 -
比如 :
客户端1向服务器发起请求 - 服务器确认客户端1的身份 - 处理 - 响应 - 断开
客户端1向服务器发起请求 - 服务器确认客户端1的身份 - 处理 - 响应 - 断开
服务器主动向客户端推送消息
WeChat - 微信
‘你’发送一条微信 - 给服务器 - ‘你好!’ - 服务器收到消息 - 服务器寻找 ‘我’ - 对着我的连接 (客户端) - 发送 你好!
WeChatPay
AliPay
1.轮询 对客户端 以及服务器要求最高
客户端轮询 - 由客户端向服务器发起请求 每秒10次左右(QPS 每秒发起请求的次数限制)
场景模拟
传达室 收发快递模型
1.大爷(接收快递) - 小二 半年之后 扔掉
2.大爷(接收快递) - 小二 -小二从宿舍跑到传达室
- 问大爷 有我快递吗?
-大爷回答:你丫谁呀? 我是大三小二
- 我知道了,你找我什么事儿? - 小二 : 有我快递吗? - 大爷:我给你找找,没找着,你回去把,一会过来
- 小二 :大爷再见 再见 再见 再见
- 小二到宿舍想起来快递没拿
- 又去传达室取快递(重复上面的过程)
- 很多个小二 同事问大爷快递
知道很久以后
- 小二 我是大三的小二
- 我知道了,你汇总啊我什么事儿?
- 小二 : 有我快递吗?
- 大爷: 我这儿真有你的快递
- 小二 拿走快递,飞奔二区
- 小二:大爷再见 再见 再见 再见
小资源访问时 优势很明显 - 因为客户端较少
2.长轮询
服务器长轮询 - 服务器不响应客户端而是将连接暂时保持住 5 秒之后 没有消息,响应客户端
一定时间之后 5s之后 断开连接, 客户端重新发起请求
情景模拟:
大爷(接收快递) - 小二
传达室装修了 - 建立了一个茶室 - 服务升级了
小二到传达室 - 问大爷有我快递吗?
- 大爷: 你丫谁呀?
- 小二:我是大三小二
- 大爷:我知道了,你找我什么事儿?
- 小二: 有我快递吗?
- 大爷:进屋做做,屋里有差,我给你找找快递
- 小二喝茶中。。。。。。
- 大爷:你多等会
- 小二喝茶中。。。。。。
- 大爷:你多等会
- 小二喝茶中。。。。。。
- 小二: 大爷,我去趟厕所
- 断开
- 小二上完厕所,不对呀,我又不是去喝茶的
- 小二来到传达室 loop
小二到传达室 - 问大爷有我快递吗?
- 大爷: 你丫谁呀?
- 小二:我是大三小二
- 大爷:我知道了,你找我什么事儿?
- 小二: 有我快递吗?
- 大爷:进屋做做,屋里有差,我给你找找快递
- 小二喝茶中。。。。。。
- 大爷说 找到了,你的快递
- 小二拿着快递美美的回去了 断开了
优势:
小二不用那么累了 客户端不用大量QPS
劣势:
传达室的茶室空间 严重浪费服务器资源
大爷学会了影分身 开启多线程服务客户端
3.长连接 客户端和 服务器资源 消耗没有那么严重了
连接保持 - Http 发起请求在请求中写一个协议 - WebSocket - 收到请求,自动保持此连接 - 永久不断开, 除非主动断开 - 可以通过此连接主动找到客户端
场景模拟
大爷(接收快递) - 小二
传达室进入信息化时代,装电话了 2万台电话
小二到传达室 - 问大爷有我快递吗?
- 大爷: 你丫谁呀?
- 小二:我是大三小二
- 大爷:我知道了,你找我什么事儿?
- 小二: 有我快递吗?
- 大爷:你把电话号码留下,回去等我电话,接了之后别挂
- 小二回到宿舍证号听见大爷来电话了
- 小二接电话 , 对面,我是你大爷,电话别挂,随时听着,有快递就过来取
- 保持通话
优势:数据实时性
劣势:服务器和客户端需要一个线程来等待消息
玩游戏:一个服务器有资源限制,所以分区,很多个服务器
服务器 完成 IO多路复用
2 . GeventWebsocket + Flask
Web (Http) + Socket (连接保持)
Flask中运行WebSocket - GeventWebsocket
wsgi?
wsgi ---> envir ---> view
wsgi ---> http ---> envir ---> view
wsgi ---> websockethandler ---> envir ---> view
websockethandler 监听了 请求头中的?
ws environ 和 headers
ws请求 environ 原始信息
{'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='' 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': , 'wsgi.input_terminated': True, 'wsgi.websocket_version': '13', 'wsgi.websocket': , 'werkzeug.request': }
'wsgi.websocket':
http environ
#{'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='' 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': , 'wsgi.input_terminated': True, 'werkzeug.request': }
http - readers
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, …}
ws - headers
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 代码:
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, …}
readyState: 0
0 连接没有建立好
1 建立好了 保持连接
2 客户端主动断开 (因为是客户端的,看不出来,不是服务器发的)
3 服务器主动断开连接 (1次就断开)
VM258:1 WebSocket is already in CLOSING or CLOSED state.