@WillireamAngel
2018-06-25T06:43:18.000000Z
字数 5102
阅读 1164
Python
socket,套接字,是应用在应用层和传输层之间的抽象层,将TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用以实现进程在网络中的通信。
socket的基本表示形式:IP+协议+端口。
socket是一种"打开—读/写—关闭"模式的实现,服务器和客户端各自维护一个"文件",在建立连接打开后,可以读取对方内容或者向自己文件写入内容供对方读取,通讯结束时关闭文件。
通信流程
- 服务器根据地址类型(ipv4,ipv6)、socket类型、协议创建socket
服务器为socket绑定ip地址和端口号;- 服务器socket监听端口号请求,随时准备接收客户端发来的连接,这时候服务器的socket并没有被打开;
- 客户端创建socket;
- 客户端打开socket,根据服务器ip地址和端口号试图连接服务器socket;
- 服务器socket接收到客户端socket请求,被动打开,开始接收客户端请求,直到客户端返回连接信息。这时候socket进入阻塞状态,所谓阻塞即accept()方法一直到客户端返回连接信息后才返回,开始接收下一个客户端请求;
- 客户端连接成功,向服务器发送连接状态信息;
- 服务器accept()方法返回,连接成功;
- 客户端向socket写入信息;
- 服务器读取信息;
- 客户端关闭;
- 服务器端关闭。
python socket模块支持建立和处理socket连接。
参照:https://docs.python.org/3/library/socket.html
server_socket:
import socket
server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
hostname = socket.gethostname()
port = 1234
server_socket.bind((hostname,port))
server_socket.listen(5)
while True:
client_socket, addr = server_socket.accept()
print('connect_address:%s' %str(addr))
msg='welcome to socket test!'+'\r\n'
client_socket.send(msg.encode('utf-8'))
client_socket.close()
client_socket:
import socket
client_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
hostname = socket.gethostname()
port = 1234
client_socket.connect((hostname,port))
msg = client_socket.recv(1024)
client_socket.close()
print(msg.decode('utf-8'))
执行python3 server_sock
和python3 client_sock
分别得到如下信息:
connect_address:('192.168.152.1', 5892)
welcome to socket test!
参照:https://docs.python.org/3/library/socket.html
了解了socket的大概知识,就谈谈Websocket。
WebSocket是一种在单个TCP连接上进行全双工通讯的协议,在HTML5中定义了WebSocket协议。WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
基于单TCP连接的双向通信和基于多TCP连接的单向通信相比,很显著地节约了用于创建TCP连接的服务器资源和带宽,极大地提高了通信效率,通讯更加实时。
- 较少的控制开销。创建连接后,服务器和客户端之间交换数据时的数据包头部产生的开销明显减少了。
- 更强的实习性。协议是全双工的,服务器可以主动给客户端下发资源,相对于单向监听等待和长轮询,延迟明显较少,短时间内能传递更多的数据。
- 保持连接状态。HTTP本身无状态,状态认证实现需要Cookie和Session等,而WebSocket本身是建立在连接基础上的,使得其成为一种有状态的协议。
- 更好的二进制支持。WebScoket定义了二进制帧,可以更轻松地处理二进制内容。
- 可以支持扩展。WebSocket定义了扩展,用户可以扩展协议。
- 更好的压缩效果。WebSocket在适当的扩展支持下,可以沿用之前的上下文,在传递类似数据时,可提高压缩率。
目前支持WebSocket的服务器有很多,主要包括php,ruby,TomCat、node.js、nginx、python、Django等。
安装websockets模块:
pip install websockets
本文以python实现WebSocket示例:
websocket_server:
import asyncio
import websockets
async def hello(websocket,path):
name = await websocket.recv()
print(f"< {name}")
greeting = f"hello {name}!"
await websocket.send(greeting)
print(f"> {greeting}")
start_server = websockets.serve(hello, 'localhost', 8765)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
websocket_client:
import asyncio
import websockets
async def hello():
async with websockets.connect(
'ws://localhost:8765') as websocket:
name = input("What's your name? ")
await websocket.send(name)
print(f"> {name}")
greeting = await websocket.recv()
print(f"< {greeting}")
asyncio.get_event_loop().run_until_complete(hello())
上例涉及到asyncio
异步I/O,相关的操作可以参考:
https://docs.python.org/3/library/asyncio.html
谈及websocket的服务端通信和二进制支持,我们很容易想到HTTP2.0的新特性。
HTTP/2.0,超文本传输协议 v2.0,是下一代HTTP协议,由互联网工程任务组(IETF)的Hypertext Transfer Protocol Bis (httpbis)工作小组进行开发,将全面用于HTTPS,实际上是在性能提升的同时增加了安全性。
(相对于HTTP1.1)
作为HTTP1.1的大版本跨越,HTTP 2.0把解决性能问题的方案内置在了传输层,添加二进制帧分层,通过多路复用来减少延迟,通过压缩 HTTP首部降低开销,同时增加请求优先级和服务器端推送的功能。
支持多路复用
每个来源一个连接,多路复用允许同时通过单一的 HTTP 2.0 连接发起多重的请求-响应消息,即所有HTTP 2.0 连接都是持久化的,而且客户端与服务器之间也只需要一个连接即可,所有数据流共用同一个连接 ,减少了因http链接多而引起的网络拥塞(在 HTTP1.1 协议中,同一时间,浏览器会针对同一域名下的请求有一定数量限制),解决了慢启动针对突发性和短时性的http链接低效的问题。
流控制是一种阻止发送方向接收方发送大量数据的机制,以免超出后者的需求或处理能力。
将通信的基本单位缩小为帧
请求和响应复用:客户端和服务器可以将 HTTP 消息分解为互不依赖的帧,然后交错发送,最后再在另一端把它们重新组装起来。
HTTP/2 中的新二进制分帧层解决了 HTTP/1.x 中存在的队首阻塞问题,也消除了并行处理和发送请求及响应时对多个连接的依赖。结果,应用速度更快、开发更简单、部署成本更低。
首部压缩
http 2.0支持DEFLATE和HPACK 算法的压缩,经过专门设计,可以解决发现的安全问题、实现起来也更高效和简单,可以对 HTTP 标头元数据进行良好压缩。(动态索引表)
请求优先级
HTTP 2.0 使用一个31比特的优先值,0表示最高优先级, 2(31)-1表示最低优先级,服务器端就可以根据优先级,控制资源分配,优先处理和返回最高优先级的请求帧给客户端。
服务端推送
客户端请求之前发送数据的机制,在 HTTP2.0 中,服务器可以对客户端的一个请求发送多个响应,可推送额外的信息。
WebSocket和HTTP/2.0有一个类似的特性,支持服务端推送(HTTP2.0)或者双向通信(WebSocket),但实际上从设计目标和支持上都大有不同。
支持
WebSocket基于HTTP1.1,提供丰富的用于TCP单连接双向传输的API,目前还不能用于HTTP2.0的链路上而HTTP2.0则是对HTML、CSS等JS资源的传输方式进行了优化,并没有提供新的JS API,也不能用于实时传输消息。如果需要实时传输消息,现在还是需要SSE、WebSocket。
设计目标
HTTP2.0:
服务端推送
服务器可以对一个客户端请求发送多个响应。 换句话说,除了对最初请求的响应外,服务器还可以向客户端推送额外资源,而无需客户端明确地请求。
一个典型的网络应用包含多种资源,客户端需要检查服务器提供的文档才能逐个找到它们。那为什么不让服务器提前推送这些资源,从而减少额外的延迟时间呢?服务器已经知道客户端下一步要请求什么资源,这时候服务器推送即可派上用场。
简言之,服务端推送是一种页面请求优化。HTTP/2 只是更加聪明的HTTP,例如你请求页面的时候能将页面和里面的样式一起返回,但并不具有可编程的能力(例如在要求的某个时刻返回某个数据)。
WebSocket:
双向通信
在建立连接后,WebSocket服务器和Browser/Client Agent都能主动的向对方发送或接收数据,就像Socket一样,不再限制于关联的推送信息,也不再限制于单次推送等。通过类似TCP的客户端和服务器端通过握手连接,连接成功后才能相互通信,而通信过程实时性较高,两端具有相同地主动发送任意信息的能力。
相同 vs 不同
相同点:
都是基于TCP的应用层协议;
都使用Request/Response模型进行连接的建立;
在连接的建立过程中对错误的处理方式相同,在这个阶段WS可能返回和HTTP相同的返回码;
都可以在网络中传输数据。不同点:
WS使用HTTP来建立连接,但是定义了一系列新的header域,这些域在HTTP中并不会使用;
WS的连接不能通过中间人来转发,它必须是一个直接连接;
WS连接建立之后,通信双方都可以在任何时刻向另一方发送数据;
WS连接建立之后,数据的传输使用帧来传递,不再需要Request消息;
WS的数据帧有序。