1.什么是websocket

websocketHTML5出的协议,和HTTP协议没有什么关系,它的目的在于,在浏览器和服务器之间建立一个不受限制的双向实时通信的通道,比如服务器可以任意时刻向浏览器主动的推送消息

它基于TCP,先通过HTTP/HTTPS协议发起一条特殊的HTTP请求进行握手后创建一个用于交换数据的TCP连接

他们是并行的关系

HTTP和WebScoket的区别

  • HTTP不支持常久的连接(长连接\循环连接等不算)
  • WebScket和服务器只要一次握手动作,HTTP协议每次链接都需要三次握手才能发送消息
  • 服务器和浏览器都可以在任意时刻相互的推送消息,HTTP的缺点就在于此,浏览器不主动请求,服务器就没法给浏览器发送数据
  • HTTP协议每次请求都要发送请求头,websocket一旦建立连接,之后请求都不用发送请求头

虽然HTTP可以用轮询或者comet机制实现WebSocket的功能,但是,每次轮询,就算是再快,也需要间隔时间,这样就造成了它的实时性不够,而且, 频繁的发送请求,会给服务器造成很大的压力,一般情况下,没人会这么做

  • 轮询:js启动定时发送请求,间隔性的请求服务器是否有新的数据
  • comet:请求没有超过预定时间或者没有返回数据,一直保持连接状态,等有了数据再进行推送

comet虽然是实时性够了,但是,长时间挂起线程,会浪费服务器的资源,如果长时间没有数据,链路上的任何一个网关都可能关闭这个链接。

所以,会造成两个后果,要么,你不知道什么时候断开了,要么,你就定期发ping,检查连接是否正常

2.什么是三次握手,四次挥手

这是基于TCP协议的规则,建立TCP需要三次握手才能建立,而断开连接则需要四次挥手

三次握手

第一次握手,客户端发送一个待SYN表之的TCP报文到服务器

第二次握手,服务器回应客户端,发送一个带有SYN和ACK标志的报文,表示它对客户端SYN报文的回应,同时询问客户端是否准备好进行数据通讯

第三次握手,客户端必须再次回应服务器一个ACK报文

四次挥手

第一次挥手,客户端发送一个FIN,用来关闭客户到服务器的数据传送

第二次挥手,服务器收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号。

第三次挥手,服务器关闭客户端的连接,发送一个FIN给客户端

第四次挥手,客户段发回ACK报文确认,并将确认序号设置为收到序号加1

由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。

3.WebSocket的使用

1.首先需要一个dwebsocket依赖,安装非常简单,直接pip install dwebsocket

2.在settings中需要注册加载,INSTALLED_APPS注册dwebsocket

dwebsocketdjango3.1之后自动加载,在这之前,都需要进行注册这一步骤

3.导包from dwebsocket.decorators import accept_websocket

4.写一个视图函数,需要用**@accept_websocket**,这样,声明了他是一个webscoket连接,这只是链接,不是发送消息,这里,定义了一个公共字典clients,一会儿要用,记住它

clients = {{

@accept_websocket
def websocketlink(request):
    if request.is_websocket():
		userid = uuid.uuid1()
        while True:
            message = request.websocket.wait()
            if not message:
                break
            else:
                clients[userid] = request.websocket

dwebsocket有两种装饰器:require_websocketaccept_websocekt
使用require_websocket装饰器会导致视图函数无法接收导致正常的http请求,一般情况使用accept_websocket方式就可以了

5.在前端,发送一个连接,注意,此时后端的链接不是http,而是ws

// websocket连接
if('WebSocket' in window){
    //  生成websocket链接
    var ws = new WebSocket('ws://127.0.0.1:8000/websocketlink/');
    // 发送链接
        ws.onopen = function(){
            ws.send('你好啊世界');
        {
    // 发送消息
    ws.onmessage=(evt)=>{
        // 将获取信息打印
        var received_msg = evt.data;
        
        this.$notification.open({
                message:received_msg
            {)

        ws.onclose = function(){
            console.log('链接已关闭')
        {
    {

6.推送消息接口,一个函数视图举例:

def sendmessage(request):
	# 获取消息
    msg = request.GET.get('msg')
    # 循环公共字典clients,遍历内部所有的链接,
    for client in clients:
        clients['client'].send(msg.encode('utf-8'))
    return HttpResponse({'message':"ok"{)

然后,链接成功后,再新打开一个页面,访问这个sendmessage方法,就可以在你的前端页面看到你发送的数据啦