WebSocket

HTML5定义了WebSocket协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。

在2008年诞生,2011年成为国际标准。

现在基本所有浏览器都已经支持了。

WebSocket是一种在单个TCP连接上进行全双工通信的协议。在WebSocket API中,浏览器和服务器只需要完成一次握手(不是指建立TCP连接的那个三次握手,是指在建立TCP连接后传输一次握手数据),两者之间就直接可以创建持久性的连接,并进行双向数据传输。

Websocket使用ws或wss的统一资源标志符,类似于HTTPS,其中wss表示在TLS之上的Websocket。如:

  1. ws://example.com/wsapi wss://secure.example.com/

Websocket使用和 HTTP 相同的 TCP 端口,可以绕过大多数防火墙的限制。默认情况下,Websocket协议使用80端口;运行在TLS之上时,默认使用443端口。

握手协议

WebSocket 是独立的、创建在 TCP 上的协议。 报文

Websocket 通过 HTTP/1.1 协议的101状态码进行握手。

为了创建Websocket连接,需要通过浏览器发出请求,之后服务器进行回应,这个过程通常称为“握手”(handshaking)。

一个典型的Websocket握手请求如下:

客户端请求

  1. GET / HTTP/1.1
  2. Upgrade: websocket
  3. Connection: Upgrade
  4. Host: example.com
  5. Origin: http://example.com
  6. Sec-WebSocket-Key: sN9cRrP/n9NdMgdcy2VJFQ==
  7. Sec-WebSocket-Version: 13

服务器回应

  1. HTTP/1.1 101 Switching Protocols
  2. Upgrade: websocket
  3. Connection: Upgrade
  4. Sec-WebSocket-Accept: fFBooB7FAkLlXgRSz0BT3v4hq5s=
  5. Sec-WebSocket-Location: ws://example.com/
  • Connection必须设置Upgrade,表示客户端希望连接升级。
  • Upgrade字段必须设置Websocket,表示希望升级到Websocket协议。
  • Sec-WebSocket-Key是随机的字符串,服务器端会用这些数据来构造出一个SHA-1的信息摘要。把“Sec-WebSocket-Key”加上一个特殊字符串“258EAFA5-E914-47DA-95CA-C5AB0DC85B11”,然后计算SHA-1摘要,之后进行BASE-64编码,将结果做为“Sec-WebSocket-Accept”头的值,返回给客户端。如此操作,可以尽量避免普通HTTP请求被误认为Websocket协议。
  • Sec-WebSocket-Version 表示支持的Websocket版本。RFC6455要求使用的版本是13,之前草案的版本均应当弃用。
  • Origin字段是可选的,通常用来表示在浏览器中发起此Websocket连接所在的页面,类似于Referer。但是,与Referer不同的是,Origin只包含了协议和主机名称。
  • 其他一些定义在HTTP协议中的字段,如Cookie等,也可以在Websocket中使用。

优点

  • 较少的控制开销。在连接创建后,服务器和客户端之间交换数据时,用于协议控制的数据包头部相对较小。在不包含扩展的情况下,对于服务器到客户端的内容,此头部大小只有2至10字节(和数据包长度有关);对于客户端到服务器的内容,此头部还需要加上额外的4字节的掩码。相对于HTTP请求每次都要携带完整的头部,此项开销显著减少了。
  • 更强的实时性。由于协议是全双工的,所以服务器可以随时主动给客户端下发数据。相对于HTTP请求需要等待客户端发起请求服务端才能响应,延迟明显更少;即使是和Comet等类似的长轮询比较,其也能在短时间内更多次地传递数据。
  • 保持连接状态。与HTTP不同的是,Websocket需要先创建连接,这就使得其成为一种有状态的协议,之后通信时可以省略部分状态信息。而HTTP请求可能需要在每个请求都携带状态信息(如身份认证等)。 更好的二进制支持。Websocket定义了二进制帧,相对HTTP,可以更轻松地处理二进制内容。
  • 可以支持扩展。Websocket定义了扩展,用户可以扩展协议、实现部分自定义的子协议。如部分浏览器支持压缩等。
  • 更好的压缩效果。相对于HTTP压缩,Websocket在适当的扩展支持下,可以沿用之前内容的上下文,在传递类似的数据时,可以显著地提高压缩率。
  • 没有同源限制,客户端可以与任意服务器通信。
  • 可以发送文本,也可以发送二进制数据。
 
 

Socket.IO

1 简介

Socket.IO 本是一个面向实时 web 应用的 JavaScript 库,现在已成为拥有众多语言支持的Web即时通讯应用的框架。

Socket.IO 主要使用WebSocket协议。但是如果需要的话,Socket.io可以回退到几种其它方法,例如Adobe Flash Sockets,JSONP拉取,或是传统的AJAX拉取,并且在同时提供完全相同的接口。尽管它可以被用作WebSocket的包装库,它还是提供了许多其它功能,比如广播至多个套接字,存储与不同客户有关的数据,和异步IO操作。

Socket.IO 不等价于 WebSocket,WebSocket只是Socket.IO实现即时通讯的其中一种技术依赖,而且Socket.IO还在实现WebSocket协议时做了一些调整。

优点:

Socket.IO 会自动选择合适双向通信协议,仅仅需要程序员对套接字的概念有所了解。

有Python库的实现,可以在Python实现的Web应用中去实现IM后台服务。

缺点:

Socket.io并不是一个基本的、独立的、能够回退到其它实时协议的WebSocket库,它实际上是一个依赖于其它实时传输协议的自定义实时传输协议的实现。该协议的协商部分使得支持标准WebSocket的客户端不能直接连接到Socket.io服务器,并且支持Socket.io的客户端也不能与非Socket.io框架的WebSocket或Comet服务器通信。因而,Socket.io要求客户端与服务器端均须使用该框架。

2 Python服务器端开发

安装

  1. pip install python-socketio

创建服务器

  • 方式1

    使用多进程多线程模式的WSGI服务器对接(如uWSGI、gunicorn)

    1. import socketio
    2.  
    3. # create a Socket.IO servers
    4. sio = socketio.Server()
    5.  
    6. # 打包成WSGI应用,可以使用WSGI服务器托管运行
    7. app = socketio.WSGIApp(sio) # Flask Django

    创建好app对象后,使用uWSGI、或gunicorn服务器运行此对象。

  • 方式2

    作为Flask、Django 应用中的一部分

    1. from wsgi import app # a Flask, Django, etc. application
    2. import socketio
    3.  
    4. # create a Socket.IO server
    5. sio = socketio.Server()
    6.  
    7. app = socketio.WSGIApp(sio, app)

    创建好app对象后,使用uWSGI、或gunicorn服务器运行此对象。

  • 方式3

    使用协程的方式运行 (推荐)

    1. import eventlet
    2. eventlet.monkey_patch()
    3.  
    4. import socketio
    5. import eventlet.wsgi
    6.  
    7. sio = socketio.Server(async_mode='eventlet') # 指明在evenlet模式下
    8. app = socketio.Middleware(sio)
    9. eventlet.wsgi.server(eventlet.listen(('', 8000)), app)
说明

因为服务器与客户端进行即时通信时,会尽可能的使用长连接,所以若服务器采用多进程或多线程方式运行,受限于服务器能创建的进程或线程数,能够支持的并发连接客户端不会很高,也就是服务器性能有限。采用协程方式运行服务器,可以提升即时通信服务器的性能。

事件处理

不同于HTTP服务的编写方式,SocketIO服务编写不再以请求Request和响应Response来处理,而是对收发的数据以消息(message)来对待,收发的不同类别的消息数据又以事件(event)来区分。

原本HTTP服务编写中处理请求、构造响应的视图处理函数在SocketIO服务中改为编写收发不同事件的事件处理函数。

1)事件处理方法

编写事件处理方法,可以接收指定的事件消息数据,并在处理方法中对消息数据进行处理。

  1. @sio.on('connect')
  2. def on_connect(sid, environ):
  3. """
  4. 与客户端建立好连接后被执行
  5. :param sid: string sid是socketio为当前连接客户端生成的识别id
  6. :param environ: dict 在连接握手时客户端发送的握手数据(HTTP报文解析之后的字典)
  7. """
  8. pass
  9.  
  10. @sio.on('disconnect')
  11. def on_disconnect(sid):
  12. """
  13. 与客户端断开连接后被执行
  14. :param sid: string sid是断开连接的客户端id
  15. """
  16. pass
  17.  
  18. # 以字符串的形式表示一个自定义事件,事件的定义由前后端约定
  19. @sio.on('my custom event')
  20. def my_custom_event(sid, data):
  21. """
  22. 自定义事件消息的处理方法
  23. :param sid: string sid是发送此事件消息的客户端id
  24. :param data: data是客户端发送的消息数据
  25. """
  26. pass
注意
  • connect 为特殊事件,当客户端连接后自动执行
  • disconnect 为特殊事件,当客户端断开连接后自动执行

  • connect、disconnect与自定义事件处理方法的函数传入参数不同

2)发送事件消息

  • 群发

    1. sio.emit('my event', {'data': 'foobar'})
  • 给指定用户发送

    1. sio.emit('my event', {'data': 'foobar'}, room=user_sid)
  • 给一组用户发送

    SocketIO提供了房间(room)来为客户端分组

    • sio.enter_room(sid, room_name)

      将连接的客户端添加到一个room

      1. @sio.on('chat')
      2. def begin_chat(sid):
      3. sio.enter_room(sid, 'chat_users')

      注意:当客户端连接后,socketio会自动将客户端添加到以此客户端sid为名的room中

    • sio.leave_room(sid, room_name)

      将客户端从一个room中移除

      1. @sio.on('exit_chat')
      2. def exit_chat(sid):
      3. sio.leave_room(sid, 'chat_users')
    • sio.rooms(sid)

      查询sid客户端所在的所有房间

      给一组用户发送消息的示例

      1. @sio.on('my message')
      2. def message(sid, data):
      3. sio.emit('my reply', data, room='chat_users')

      也可在群组发消息时跳过指定客户端

      1. @sio.on('my message')
      2. def message(sid, data):
      3. sio.emit('my reply', data, room='chat_users', skip_sid=sid)
  • 使用send发送message事件消息

    对于'message'事件,可以使用send方法

    1. sio.send({'data': 'foobar'})
    2. sio.send({'data': 'foobar'}, room=user_sid)

3 Python客户端

  1. import socketio
  2.  
  3. sio = socketio.Client()
  4.  
  5. @sio.on('connect')
  6. def on_connect():
  7. pass
  8.  
  9. @sio.on('event')
  10. def on_event(data):
  11. pass
  12.  
  13. sio.connect('http://10.211.55.7:8000')
  14. sio.wait()
  1.  
  1.  

即时通信WebSocket 和Socket.IO的更多相关文章

  1. AndroidAsync :异步Socket,http(client+server),websocket和socket.io的Android类库

    AndroidAsync是一个用于Android应用的异步Socket,http(client+server),websocket和socket.io的类库.基于NIO,没有线程.它使用java.ni ...

  2. websocket与socket.io

    什么是Websocket? Websocket是一个独立于http的实时通信协议,最初是在HTML5中被引用进来的,在HTML5规范中作为浏览器与服务器的核心通信技术被嵌入到浏览器中.WebSocke ...

  3. websocket 与Socket.IO介绍

    一  websocket WebSocket是html5新增加的一种通信协议,目前流行的浏览器都支持这个协议,例如 Chrome,Safrie,Firefox,Opera,IE等等,对该协议支持最早的 ...

  4. .net , java webSocket 连接 Socket.io (1.4.4版本) 问题

    .net版Socketio4net类库和java版socket.io-java-client类库 连接socket.io 1.4版本都不行,网上大多是socket.io 0.9版本的,socket.i ...

  5. 轮询以及webSocket与socket.io原理

    概述: 首先,我们知道,起初的http协议只是为了能够进行通信而被创造出来(也就是请求-响应的过程).并没有双向通信这一说,后面随着历史业务的需求,人们使用轮询http来解决双向通信也就是使用xhr或 ...

  6. websocket 和 socket.io 之间的区别是什么

    socket.io封装了websocket,同时包含了其它的连接方式,比如Ajax.原因在于不是所有的浏览器都支持websocket,通过socket.io的封装,你不用关心里面用了什么连接方式.你在 ...

  7. websocket 和 socket.io 之间的区别

    socket.io封装了websocket,同时包含了其它的连接方式,比如Ajax.原因在于不是所有的浏览器都支持websocket,通过socket.io的封装,你不用关心里面用了什么连接方式.你在 ...

  8. Websocket --socket.io的用法

    <!DOCTYPE html> <html> <head> <title>Hello WebSocket</title> <link ...

  9. Socket.io:有点意思

    个人网站 欢迎品尝 edwardesire.com 下面页面就是使用Socket.io制作的口袋妖怪游戏(默认小屏下已隐藏,请切换到大分辨率查看).左边是游戏画面,右边是按键表和聊天室.画面达到红蓝版 ...

随机推荐

  1. 在Ngnix中配置支持Websocket

    使用SignalR实现Websocket实时数据传输时,前后端各自实现编码后,无法将Websocket调试通过.沮丧之时,负责配置网络代理的同事说,网络访问这块使用了Ngnix代理设置,可能是造成We ...

  2. 医学图像dcm2d切片文件转3dnii文件

    安装 conda: conda install -c conda-forge dicom2nifti pip: pip install dicom2nifti 更新 conda: conda upda ...

  3. dome 模块 pyaudio 声音处理 为语音识别准备

    dome 模块 pyaudio 声音处理 为语音识别准备 直接上例子 dome1 声音强度检查 import pyaudio import numpy as np class QAudio: CHUN ...

  4. Python面向对象之异常处理

    1:什么是异常 异常就是在我们的程序在运行过程中由于某种错误而引发Python抛出的错误: 异常就是程序运行时发生错误的信号(在程序出现错误时,则会产生一个异常,若程序没有处理它,则会抛出该异常,程序 ...

  5. Django之auth用户认证

    auth模块 from django.contrib import auth django.contrib.auth中提供了许多方法,这里主要介绍其中的三个: authenticate()    提供 ...

  6. 我是如何从通信转到Java软件开发工程师的?

    我的读者里面有绝大部分都是在校学生,有本科的,也有专科的,我在微信里收到很多读者的提问,大部分问题都跟如何学习编程有关,有换专业自学的.有迷茫不知道如何学习的.有报培训班没啥效果的等等,我能感受到他们 ...

  7. C语言:const关键字用法

    参考博客:https://www.cnblogs.com/bianchengzhuji/p/10335837.html const是constant的简写,是不变的意思.但并不是说它修饰常量,而是说它 ...

  8. Nginx知多少系列之(一)前言

    目录 1.前言 2.安装 3.配置文件详解 4.工作原理 5.Linux下托管.NET Core项目 6.Linux下.NET Core项目负载均衡 7.Linux下.NET Core项目Nginx+ ...

  9. MySQL入门,第七部分,单表查询

    首先我们需要了解一下整个数据库的结构 其中Student表中Sno为主键.Study表中Sno和Cno合起来做主键.Course表中Cno为主键 其创建脚本如下: #----------------- ...

  10. 3.K均值算法

    一.概念 K-means中心思想:事先确定常数K,常数K意味着最终的聚类类别数,首先随机选定初始点为质心,并通过计算每一个样本与质心之间的相似度(这里为欧式距离),将样本点归到最相似的类中,接着,重新 ...