精华内容
下载资源
问答
  • 【请采纳点赞】你可以把WebSocket看成是HTTP协议为了支持长连接所打的一个大补丁,它和HTTP有一些共性,是为了解决HTTP本身无法解决的某些问题而做出的一个改良设计。在以前HTTP协议中所谓的keep-aliveconnection是...

    【请采纳点赞】

    你可以把WebSocket看成是HTTP协议为了支持长连接所打的一个大补丁,它和HTTP有一些共性,是为了解决HTTP本身无法解决的某些问题而做出的一个改良设计。在以前HTTP协议中所谓的keep-aliveconnection是指在一次TCP连接中完成多个HTTP请求,但是对每个请求仍然要单独发header;所谓的polling是指从客户端(一般就是浏览器)不断主动的向服务器发HTTP请求查询是否有新数据。

    这两种模式有一个共同的缺点,就是除了真正的数据部分外,服务器和客户端还要大量交换HTTPheader,信息交换效率很低。它们建立的“长连接”都是伪。长连接,只不过好处是不需要对现有的HTTPserver和浏览器架构做修改就能实现。WebSocket解决的第一个问题是,通过第一个HTTPrequest建立了TCP连接之后,之后的交换数据都不需要再发HTTPrequest了,使得这个长连接变成了一个真。

    长连接。但是不需要发送HTTPheader就能交换数据显然和原有的HTTP协议是有区别的,所以它需要对服务器和客户端都进行升级才能实现。在此基础上WebSocket还是一个双通道的连接,在同一个TCP连接上既可以发也可以收信息。此外还有multiplexing功能,几个不同的URI可以复用同一个WebSocket连接。

    这些都是原来的HTTP不能做到的。另外说一点技术细节,因为看到有人提问WebSocket可能进入某种半死不活的状态。这实际上也是原有网络世界的一些缺陷性设计。上面所说的WebSocket真。长连接虽然解决了服务器和客户端两边的问题,但坑爹的是网络应用除了服务器和客户端之外,另一个巨大的存在是中间的网络链路。

    一个HTTP/WebSocket连接往往要经过无数的路由,防火墙。你以为你的数据是在一个“连接”中发送的,实际上它要跨越千山万水,经过无数次转发,过滤,才能最终抵达终点。在这过程中,中间节点的处理方法很可能会让你意想不到。比如说,这些坑爹的中间节点可能会认为一份连接在一段时间内没有数据发送就等于失效,它们会自作主张的切断这些连接。

    在这种情况下,不论服务器还是客户端都不会收到任何提示,它们只会一厢情愿的以为彼此间的红线还在,徒劳地一边又一边地发送抵达不了彼岸的信息。而计算机网络协议栈的实现中又会有一层套一层的缓存,除非填满这些缓存,你的程序根本不会发现任何错误。这样,本来一个美好的WebSocket长连接,就可能在毫不知情的情况下进入了半死不活状态。

    而解决方案,WebSocket的设计者们也早已想过。就是让服务器和客户端能够发送Ping/PongFrame(RFC6455-TheWebSocketProtocol)。这种Frame是一种特殊的数据包,它只包含一些元数据而不需要真正的DataPayload,可以在不影响Application的情况下维持住中间网络的连接状态。

    全部

    展开全文
  • websocket

    千次阅读 2020-12-21 04:54:07
    // 构造一个websocket实例, var ws = new WebSocket('ws://localhost:8080') ws.readyState // 查看其连接状态 实例化 new WebSocket('ws://localhost:8080') 后将会自动发送握手消息到服务端进行连接,通过 ws....

    websocket

    http是一种无状态的连接,并且它只能由客户端发起请求,然后服务端返回响应,服务端无法自动向客户端推送消息,最常见的就是早期实现的web聊天功能,在没有webscoket的时候,通常通过长轮询的方式处理。

    长轮询:客户端发送ajax请求尝试获取消息,服务器为每个客户端维护一个消息队列,而客户端请求从这个队列中取出消息,如果队列没有数据,将会再次阻塞一段时间,经过一段时间,或者获得了数据,将会直接返回,将数据返回给客户端,然后再发送一个请求继续尝试获取消息。

    长轮询的效率低,浪费资源, 需要定时不断的发送http请求,并占用http连接,而websocket可以方便的完成服务器向客户端推送消息功能,实现上面的功能。

    其他特点包括:

    (1)建立在 TCP 协议之上,服务器端的实现比较容易。

    (2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,能通过各种 HTTP 代理服务器。

    (3)数据格式比较轻量,性能开销小,通信高效。

    (4)可以发送文本,也可以发送二进制数据。

    (5)没有同源限制,客户端可以与任意服务器通信。

    (6)协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。

    websocket连接实现原理

    握手

    客户端生成一个随机的字符串,放在http请求头中发送到服务器端,服务器获得全球公认的magic-string字符串,将两个字符串进行拼接,然后使用公认的算法(sha1 + base64)对这个字符串进行加密,将加密后的内容返回到客户端,客户端同样获取magic-string进行相同的加密,如果两个密文相同,表示服务器支持websocket协议。服务器和客户端可以使用websocket协议进行通信。

    使用这个随机字符串的连接方式主要作用在于提供基础的防护,减少恶意连接、意外连接。他并不能连接和数据得安全,因为这些算法都是公开且比较简单。

    数据通信

    建立连接后,双发可以通过websocket协议发送和接受消息,而这些消息都是进过加密发送的,且加密和解密方法全球公认。

    数据解密步骤:

    1. 取数据的第二个字节的后7位,该十进制值可能为127,126, <125三种情况

    - 值为127,从数据的第11个字节开始读取

    - 值为126,从数据的第4个字节开始读取

    - 值<125,从数据的第三个字节开始读取

    2. 这样读取的内容除去了前面的头信息,是我们需要的消息体,但是还需要经过位运进行解密。消息体的数据前四个字节位mask,该值将与之后的每个字节进行指定的位运算,才能得到加密前的字节序列,从而decode得到可阅读字符串消息。

    python实现websocket服务端

    importsocketimporthashlibimportbase64defget_headers(data):"""解析这个data的头信息,将header解析为一个字典"""header_dict={}

    data= str(data, encoding='utf-8')

    header, body= data.split('\r\n\r\n', 1)

    header_list= header.split('\r\n')for i inrange(0, len(header_list)):if i ==0:if len(header_list[i].split(' ')) == 3:

    header_dict['method'], header_dict['url'], header_dict['protocol'] = header_list[i].split(' ')else:

    k, v= header_list[i].split(':', 1)

    header_dict[k]=v.strip()returnheader_dictdefget_data(info):

    payload_len= info[1] & 127

    if payload_len == 126:

    extend_payload_len= info[2:4]

    mask= info[4:8]

    decoded= info[8:]elif payload_len == 127:

    extend_payload_len= info[2:10]

    mask= info[10:14]

    decoded= info[14:]else:

    extend_payload_len=None

    mask= info[2:6]

    decoded= info[6:]

    bytes_list=bytearray() # 使用bytesarray保存每个字节的数据,最后将这个字节序列进行decode得到数据for i inrange(len(decoded)):

    chunk= decoded[i] ^ mask[i % 4]

    bytes_list.append(chunk)

    body= str(bytes_list, encoding='utf-8')returnbody

    sock=socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR,1)

    sock.bind(('127.0.0.1', 8002))

    sock.listen(5)#等待客户端的连接,获取客户端socket对象,

    conn, address =sock.accept()#客户端连接后,将会自动发送随机字符串,服务器获取客户端发送的消息,然后从头信息中解析到这个随机字符串

    data = conn.recv(1024)

    header_dict=get_headers(data)

    client_random_string= header_dict['Sec-WebSocket-Key'] # 该字符串在头信息中的header的key为Sec-WebSocket-Key

    magic_string= '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'value= client_random_string +magic_string

    ac= base64.b64encode(hashlib.sha1(value.encode('utf-8')).digest()) # 加密后字符串 ac

    # 返回的头信息,将生成的密文放在Sec-WebSocket-Accept 头中进行返回

    tpl= "HTTP/1.1 101 Switching Protocols\r\n"\"Upgrade:websocket\r\n"\"Connection: Upgrade\r\n"\"Sec-WebSocket-Accept: %s\r\n"\"WebSocket-Location: ws://127.0.0.1:8002\r\n\r\n"response_str= tpl %ac.decode('utf-8')#将随机字符串给浏览器返回回去

    conn.send(bytes(response_str, encoding='utf-8'))whileTrue:

    data= conn.recv(1024) # 不断的接受客户端的消息,并使用get_data函数对消息 进行解密

    value=get_data(data)print(value)

    在浏览器的客户端,只要使用相同的方式对数据进行加解密即可实现客户端与服务端的交互。而目前的浏览器已经基本实现websocket协议,进行通信只需要使用WebSocket 对象构造函数,新建 WebSocket 实例即可。

    // 构造一个websocket实例,

    var ws = new WebSocket('ws://localhost:8080')

    ws.readyState // 查看其连接状态

    实例化 new WebSocket('ws://localhost:8080') 后将会自动发送握手消息到服务端进行连接,通过 ws.readyState 可以查看握手状态,共有四种

    CONNECTING:值为0,表示正在连接。

    OPEN:值为1,表示连接成功,可以通信了。

    CLOSING:值为2,表示连接正在关闭。

    CLOSED:值为3,表示连接已经关闭,或者打开连接失败。

    该对象常用api

    //用于指定连接成功后的回调函数

    ws.onopen = function() {

    ws.send('Hello Server!');

    }//指定多个回调函数

    ws.addEventListener('open', function(event) {

    ws.send('Hello Server!');

    });//指定连接关闭后的回调函数

    ws.onclose = function(event) {var code =event.code;var reason =event.reason;var wasClean =event.wasClean;//handle close event

    };

    ws.addEventListener("close", function(event) {var code =event.code;var reason =event.reason;var wasClean =event.wasClean;//handle close event

    });//用于指定收到服务器数据后的回调函数

    ws.onmessage = function(event) {var data =event.data;//处理数据, 数据可能是文本,也可能是二进制数据(blob对象或Arraybuffer对象)

    if(typeof event.data ===String) {

    console.log("Received data string");

    }if(event.data instanceofArrayBuffer){var buffer =event.data;

    console.log("Received arraybuffer");

    }

    };//用于向服务器发送数据//发送文本

    ws.send('your message');//发送二进制数据

    var file =document

    .querySelector('input[type="file"]')

    .files[0];

    ws.send(file);

    channel组件

    django默认没有实现websocket,需要使用channels模块,这里需要安装channel 2.3版本,pip3 install channels==2.3  并建议使用python3.6的环境,在channels的内部已经帮助我们实现了握手/加密/解密等所有环节,我们只需要简单实现数据的收发即可。

    集成channels

    1. 在settings的app列表中注册chennel的app,并指定Asgi应用路径

    INSTALLED_APPS =['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles',#项目中要使用channels做websocket了.

    "channels",

    ]

    ASGI_APPLICATION= "channel_demo.routing.application" #指向一个模块中的变量

    2. 实现websocket协议

    from channels.routing importProtocolTypeRouter, URLRouterfrom django.conf.urls importurlfrom app importconsumers

    application= ProtocolTypeRouter({ #使用websockket协议通信时候的url路径映射

    'websocket': URLRouter([

    url(r'^chat/$', consumers.ChatConsumer), #这里交给app.consumer中的一个类处理该请求

    ])

    })

    3. 请求的处理

    from channels.generic.websocket importWebsocketConsumerfrom channels.exceptions importStopConsumerclassChatConsumer(WebsocketConsumer):defwebsocket_connect(self, message):"""客户端发来连接请求之后就会被触发"""

    #服务端接收连接,向客户端浏览器发送一个加密字符串

    self.accept()#连接成功

    CONSUMER_OBJECT_LIST.append(self)defwebsocket_receive(self, message):"""浏览器向服务端发送消息,此方法自动触发,

    :param message: {"type": , "text":"客户端发送的数据"}"""

    #服务端给客户端回一条消息

    self.send(text_data=message['text'])defwebsocket_disconnect(self, message):"""客户端主动断开连接"""

    #服务端断开连接

    raise StopConsumer()

    展开全文
  • 看完让你彻底搞懂Websocket原理

    千次阅读 2020-12-21 04:55:09
    偶然在知乎上看到一篇回帖,瞬间觉得之前看的那么多...废话这么多了,最后再赞一个~一、websocket与httpWebSocket是HTML5出的东西(协议),也就是说HTTP协议没有变化,或者说关系,但HTTP是不支持持久连接的(长连...

    偶然在知乎上看到一篇回帖,瞬间觉得之前看的那么多资料都不及这一篇回帖让我对 websocket 的认识深刻有木有。所以转到我博客里,分享一下。比较喜欢看这种博客,读起来很轻松,不枯燥,没有布道师的阵仗,纯粹为分享。废话这么多了,最后再赞一个~

    一、websocket与http

    WebSocket是HTML5出的东西(协议),也就是说HTTP协议没有变化,或者说没关系,但HTTP是不支持持久连接的(长连接,循环连接的不算)

    首先HTTP有 1.1 和 1.0 之说,也就是所谓的 keep-alive ,把多个HTTP请求合并为一个,但是 Websocket 其实是一个新协议,跟HTTP协议基本没有关系,只是为了兼容现有浏览器的握手规范而已,也就是说它是HTTP协议上的一种补充可以通过这样一张图理解

    有交集,但是并不是全部。

    另外Html5是指的一系列新的API,或者说新规范,新技术。Http协议本身只有1.0和1.1,而且跟Html本身没有直接关系。。通俗来说,你可以用HTTP协议传输非Html数据,就是这样=。=

    再简单来说,层级不一样。

    二、Websocket是什么样的协议,具体有什么优点

    首先,Websocket是一个持久化的协议,相对于HTTP这种非持久的协议来说。简单的举个例子吧,用目前应用比较广泛的PHP生命周期来解释。

    HTTP的生命周期通过 Request 来界定,也就是一个 Request 一个 Response ,那么在 HTTP1.0 中,这次HTTP请求就结束了。

    在HTTP1.1中进行了改进,使得有一个keep-alive,也就是说,在一个HTTP连接中,可以发送多个Request,接收多个Response。但是请记住 Request = Response, 在HTTP中永远是这样,也就是说一个request只能有一个response。而且这个response也是被动的,不能主动发起。

    教练,你BB了这么多,跟Websocket有什么关系呢?_(:з」∠)_好吧,我正准备说Websocket呢。。

    首先Websocket是基于HTTP协议的,或者说借用了HTTP的协议来完成一部分握手。

    首先我们来看个典型的 Websocket 握手(借用Wikipedia的。。)

    GET /chat HTTP/1.1

    Host: server.example.com

    Upgrade: websocket

    Connection: Upgrade

    Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==

    Sec-WebSocket-Protocol: chat, superchat

    Sec-WebSocket-Version: 13

    Origin: http://example.com

    熟悉HTTP的童鞋可能发现了,这段类似HTTP协议的握手请求中,多了几个东西。我会顺便讲解下作用。

    Upgrade: websocket

    Connection: Upgrade

    这个就是Websocket的核心了,告诉 Apache 、 Nginx 等服务器:注意啦,我发起的是Websocket协议,快点帮我找到对应的助理处理~不是那个老土的HTTP。

    Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==

    Sec-WebSocket-Protocol: chat, superchat

    Sec-WebSocket-Version: 13

    首先, Sec-WebSocket-Key 是一个 Base64 encode 的值,这个是浏览器随机生成的,告诉服务器:泥煤,不要忽悠窝,我要验证尼是不是真的是Websocket助理。

    然后, Sec_WebSocket-Protocol 是一个用户定义的字符串,用来区分同URL下,不同的服务所需要的协议。简单理解:今晚我要服务A,别搞错啦~

    最后, Sec-WebSocket-Version 是告诉服务器所使用的 Websocket Draft (协议版本),在最初的时候,Websocket协议还在 Draft 阶段,各种奇奇怪怪的协议都有,而且还有很多期奇奇怪怪不同的东西,什么Firefox和Chrome用的不是一个版本之类的,当初Websocket协议太多可是一个大难题。。不过现在还好,已经定下来啦~大家都使用的一个东西~ 脱水: 服务员,我要的是13岁的噢→_→

    然后服务器会返回下列东西,表示已经接受到请求, 成功建立Websocket啦!

    HTTP/1.1 101 Switching Protocols

    Upgrade: websocket

    Connection: Upgrade

    Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=

    Sec-WebSocket-Protocol: chat

    这里开始就是HTTP最后负责的区域了,告诉客户,我已经成功切换协议啦~

    Upgrade: websocket

    Connection: Upgrade

    依然是固定的,告诉客户端即将升级的是 Websocket 协议,而不是mozillasocket,lurnarsocket或者shitsocket。

    然后, Sec-WebSocket-Accept 这个则是经过服务器确认,并且加密过后的 Sec-WebSocket-Key 。 服务器:好啦好啦,知道啦,给你看我的ID CARD来证明行了吧。。

    后面的, Sec-WebSocket-Protocol 则是表示最终使用的协议。

    至此,HTTP已经完成它所有工作了,接下来就是完全按照Websocket协议进行了。具体的协议就不在这阐述了。

    ——————技术解析部分完毕——————

    你TMD又BBB了这么久,那到底Websocket有什么鬼用, http long poll ,或者ajax轮询 不都可以实现实时信息传递么。

    好好好,年轻人,那我们来讲一讲Websocket有什么用。来给你吃点胡(苏)萝(丹)卜(红)

    三、Websocket的作用

    在讲Websocket之前,我就顺带着讲下 long poll 和 ajax轮询 的原理。

    ajax轮询

    ajax轮询的原理非常简单,让浏览器隔个几秒就发送一次请求,询问服务器是否有新信息。

    场景再现:

    客户端:啦啦啦,有没有新信息(Request)

    服务端:没有(Response)

    客户端:啦啦啦,有没有新信息(Request)

    服务端:没有。。(Response)

    客户端:啦啦啦,有没有新信息(Request)

    服务端:你好烦啊,没有啊。。(Response)

    客户端:啦啦啦,有没有新消息(Request)

    服务端:好啦好啦,有啦给你。(Response)

    客户端:啦啦啦,有没有新消息(Request)

    服务端:。。。。。没。。。。没。。。没有(Response) —- loop

    long poll

    long poll 其实原理跟 ajax轮询 差不多,都是采用轮询的方式,不过采取的是阻塞模型(一直打电话,没收到就不挂电话),也就是说,客户端发起连接后,如果没消息,就一直不返回Response给客户端。直到有消息才返回,返回完之后,客户端再次建立连接,周而复始。

    场景再现:

    客户端:啦啦啦,有没有新信息,没有的话就等有了才返回给我吧(Request)

    服务端:额。。 等待到有消息的时候。。来 给你(Response)

    客户端:啦啦啦,有没有新信息,没有的话就等有了才返回给我吧(Request) -loop

    从上面可以看出其实这两种方式,都是在不断地建立HTTP连接,然后等待服务端处理,可以体现HTTP协议的另外一个特点,被动性。

    何为被动性呢,其实就是,服务端不能主动联系客户端,只能有客户端发起。

    简单地说就是,服务器是一个很懒的冰箱(这是个梗)(不会、不能主动发起连接),但是上司有命令,如果有客户来,不管多么累都要好好接待。

    说完这个,我们再来说一说上面的缺陷(原谅我废话这么多吧OAQ)

    从上面很容易看出来,不管怎么样,上面这两种都是非常消耗资源的。

    ajax轮询 需要服务器有很快的处理速度和资源。(速度)long poll 需要有很高的并发,也就是说同时接待客户的能力。(场地大小)

    所以 ajax轮询 和 long poll 都有可能发生这种情况。

    客户端:啦啦啦啦,有新信息么?

    服务端:月线正忙,请稍后再试(503 Server Unavailable)

    客户端:。。。。好吧,啦啦啦,有新信息么?

    服务端:月线正忙,请稍后再试(503 Server Unavailable)

    客户端:然后服务端在一旁忙的要死:冰箱,我要更多的冰箱!更多。。更多。。(我错了。。这又是梗。。)

    言归正传,我们来说Websocket吧

    通过上面这个例子,我们可以看出,这两种方式都不是最好的方式,需要很多资源。

    一种需要更快的速度,一种需要更多的’电话’。这两种都会导致’电话’的需求越来越高。

    哦对了,忘记说了HTTP还是一个状态协议。

    通俗的说就是,服务器因为每天要接待太多客户了,是个健忘鬼,你一挂电话,他就把你的东西全忘光了,把你的东西全丢掉了。你第二次还得再告诉服务器一遍。

    所以在这种情况下出现了,Websocket出现了。他解决了HTTP的这几个难题。首先,被动性,当服务器完成协议升级后(HTTP->Websocket),服务端就可以主动推送信息给客户端啦。所以上面的情景可以做如下修改。

    客户端:啦啦啦,我要建立Websocket协议,需要的服务:chat,Websocket协议版本:17(HTTP Request)

    服务端:ok,确认,已升级为Websocket协议(HTTP Protocols Switched)

    客户端:麻烦你有信息的时候推送给我噢。。

    服务端:ok,有的时候会告诉你的。

    服务端:balabalabalabala

    服务端:balabalabalabala

    服务端:哈哈哈哈哈啊哈哈哈哈

    服务端:笑死我了哈哈哈哈哈哈哈

    就变成了这样,只需要经过一次HTTP请求,就可以做到源源不断的信息传送了。(在程序设计中,这种设计叫做回调,即:你有信息了再来通知我,而不是我傻乎乎的每次跑来问你 )

    这样的协议解决了上面同步有延迟,而且还非常消耗资源的这种情况。那么为什么他会解决服务器上消耗资源的问题呢?

    其实我们所用的程序是要经过两层代理的,即HTTP协议在Nginx等服务器的解析下,然后再传送给相应的Handler(PHP等)来处理。简单地说,我们有一个非常快速的 接线员(Nginx) ,他负责把问题转交给相应的 客服(Handler) 。

    本身接线员基本上速度是足够的,但是每次都卡在客服(Handler)了,老有客服处理速度太慢。,导致客服不够。Websocket就解决了这样一个难题,建立后,可以直接跟接线员建立持久连接,有信息的时候客服想办法通知接线员,然后接线员在统一转交给客户。

    这样就可以解决客服处理速度过慢的问题了。

    同时,在传统的方式上,要不断的建立,关闭HTTP协议,由于HTTP是非状态性的,每次都要重新传输 identity info (鉴别信息),来告诉服务端你是谁。

    虽然接线员很快速,但是每次都要听这么一堆,效率也会有所下降的,同时还得不断把这些信息转交给客服,不但浪费客服的处理时间,而且还会在网路传输中消耗过多的流量/时间。

    但是Websocket只需要一次HTTP握手,所以说整个通讯过程是建立在一次连接/状态中,也就避免了HTTP的非状态性,服务端会一直知道你的信息,直到你关闭请求,这样就解决了接线员要反复解析HTTP协议,还要查看identity info的信息。

    同时由客户主动询问,转换为服务器(推送)有信息的时候就发送(当然客户端还是等主动发送信息过来的。。),没有信息的时候就交给接线员(Nginx),不需要占用本身速度就慢的客服(Handler)了

    ——————–

    至于怎么在不支持Websocket的客户端上使用Websocket。。答案是: 不能

    但是可以通过上面说的 long poll 和 ajax 轮询 来 模拟出类似的效果

    ——————–

    内容转自知乎:http://www.zhihu.com/question/20215561

    展开全文
  • 为什么会有websocket2. websocket协议格式3. 协议具体实现一、为什么需要 WebSocket?初次接触 WebSocket 的人,都会问同样的问题:我们已经有了 HTTP 协议,为什么还需要另一个协议?它能带来什么好处?答案很简单...

    目录

    1. 为什么会有websocket

    2. websocket协议格式

    3. 协议具体实现

    一、为什么需要 WebSocket?

    初次接触 WebSocket 的人,都会问同样的问题:我们已经有了 HTTP 协议,为什么还需要另一个协议?它能带来什么好处?

    答案很简单,因为 HTTP 协议有一个缺陷:通信只能由客户端发起

    举例来说,我们想了解今天的天气,只能是客户端向服务器发出请求,服务器返回查询结果。HTTP协议做不到服务器主动向客户端推送信息。

    这种单向请求的特点,注定了如果服务器有连续的状态变化,客户端要获知就非常麻烦。我们只能使用"轮询":每隔一段时候,就发出一个询问,了解服务器有没有新的信息。最典型的场景就是聊天室。

    轮询的效率低,非常浪费资源(因为必须不停连接,或者HTTP连接始终打开)。因此,工程师们一直在思考,有没有更好的方法。WebSocket就是这样发明的

    WebSocket协议在2008年诞生,2011年成为国际标准。所有浏览器都已经支持了。

    它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。

    其他特点包括:

    1)建立在 TCP 协议之上,服务器端的实现比较容易。

    (2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。

    (3)数据格式比较轻量,性能开销小,通信高效。

    (4)可以发送文本,也可以发送二进制数据。

    (5)没有同源限制,客户端可以与任意服务器通信。

    (6)协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。

    websocket协议格式

    Browser已经支持http协议,为什么还要开发一种新的WebSocket协议呢?我们知道http协议是一种单向的网络协议,在建立连接后,它只允许Browser/UA(UserAgent)向WebServer发出请求资源后,WebServer才能返回相应的数据。而WebServer不能主动的推送数据给Browser/UA,当初这么设计http协议也是有原因的,假设WebServer能主动的推送数据给Browser/UA,那Browser/UA就太容易受到攻击,一些广告商也会主动的把一些广告信息在不经意间强行的传输给客户端,这不能不说是一个灾难。那么单向的http协议给现在的网站或Web应用程序开发带来了哪些问题呢?一条连接上只可以发送一个请求

    请求只能从客户端开始。客户端不可以接收除了响应以外的指令。

    请求 / 响应首部未经过压缩就直接进行传输。首部的信息越多,那么延迟就越大。

    发送冗长的首部。每次互相发送相同的首部造成的浪费越多

    可以任意选择数据压缩格式。非强制压缩发送

    ajax轮询

    ajax(异步的javascript与xml技术)是一种有效利用javascript和dom的操作,以达到局部web页面的提花和加载的异步通信手段。和以前的同步通信相比,他只更新一部分页面,相应中传输饿数据量会因此的减少。

    ajax轮询的原理是,让浏览器每隔一段时间就发送一次请求,询问服务器是否有新消息。

    而利用ajax实时的从服务器获取内容,有可能导致大量的请求产生。

    长轮询

    原理和ajax轮询差不多,都是采用轮询的方式,不过采用的是阻塞模型。也就是说,当客户端发起连接后,如果服务器端内容没有更新,将响应至于挂起状态,一直不回复response给客户端,知道有内容更新,再返回响应。

    虽然可以做到实时更新,但是为了保留响应,一次连接饿持续时间也变长了。期间,为了维持连接会消费更多的资源。

    从上面两种方式中,其实可以看出是再不断的建立http连接,然后等待服务器处理,可以体现出了http的特点:被动性,即:请求只能由客户端发起。服务器端不能主动联系客户端。

    不管怎么样,上面这两种都是非常消耗资源的。

    ajax轮询 需要服务器有很快的处理速度和资源。(速度)

    长轮询 需要有很高的并发,也就是说同时接待客户的能力。(场地大小)

    除了以上这些,HTTP还是一个无状态协议。

    通俗的说就是,服务器因为每天要接待太多浏览器了,是个健忘鬼,你一断连接,他就把你的东西全忘光了,把你的东西全丢掉了。你第二次还得再告诉服务器一遍。

    WebSocket

    WebSocket其实是HTTP协议上的一种补充,他们有交集但并不是全部。

    一旦web服务器和客户端建立起websocket协议的通信连接,之后所有的通信都依靠这个专用连接进行。只需要经过一次HTTP请求,就可以做到源源不断的信息传送了。

    websocket是基于HTTP协议的,或者说借用了http的协议来完成一部分握手。为了实现websocket通信,在http建立连接后,还需要进行一次“握手”的步骤。

    握手 · 请求

    GET /chat HTTP/1.1 Host: server.example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== Sec-WebSocket-Protocol: chat, superchat Sec-WebSocket-Version: 13 Origin: http://example.com

    为了实现websocket通信,需要用到http的Upgrade首部字段,告知服务器通信协议已发生改变:我要发起的是websocket协议。以达到握手的目的。

    Sec-WebSocket-Key字段记录着握手必不可少的键值,用于验证服务器是否支持websocket通信。

    Sec-WebSocket-Protocol字段记录的是所需要使用的协议。

    握手 · 响应

    HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: HsMrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol: chat

    对于客户端的请求,服务器返回状态码 101 Switching Protocols的响应。

    返回Upgrate告诉客户端即将升级的协议是Websocket协议。

    Sec-WebSocket-Accept字段值是由握手请求中的Sec-WebSocket-Key字段值加密过后生成的。

    Sec-WebSocket-Protocol 则是表明最总使用的协议。

    到这里,http已经完成所有他的工作了,接下来通信时不再使用HTTP的数据帧,而是使用websocket独立的数据帧。

    因此,websocket协议具有以下的特点:推送功能

    支持服务器端向客户端推送功能。服务器可以直接发送数据而不用等待客户端的请求。

    减少通信量

    只要建立起websocket连接,就一直保持连接,在此期间可以源源不断的传送消息,直到关闭请求。也就避免了HTTP的非状态性。

    减少资源消耗

    那么为什么他会解决服务器上消耗资源的问题呢?其实我们所用的程序是要经过两层代理的,即HTTP协议在Nginx等服务器的解析下,然后再传送给相应的Handler(PHP等)来处理。简单地说,我们有一个非常快速的接线员(Nginx),他负责把问题转交给相应的客服(Handler)。本身接线员基本上速度是足够的,但是每次都卡在客服(Handler)了,老有客服处理速度太慢。导致客服不够。Websocket就解决了这样一个难题,建立后,可以直接跟接线员建立持久连接,有信息的时候客服想办法通知接线员,然后接线员在统一转交给客户。这样就可以解决客服处理速度过慢的问题了。

    协议具体实现

    前提:

    本人最近做的项目,服务器端用的是C++写的,而与客户端交互用的是websocket,服务器端要想正常的使用数据,必须要对websocket协议进行解析。

    WebSocket数据格式

    FIN:表示这个数据是不是接收完毕,为1表示收到的数据是完整的,占1bit

    RSV1~3:用于扩展,通常都为0,各占1bit

    OPCODE:表示报文的类型,占4bit 0x00:标识一个中间数据包0x01:标识一个text数据包0x02:标识一个二进制数据包0x03~07:保留0x08:标识一个断开连接数据包0x09:标识一个ping数据包0x0A:标识一个pong数据包0x0B~F:保留

    MASK:用于表示数据是否经常掩码处理,为1时,Masking-key即存在,占1bit

    Payload len:表示数据长度,即Payload Data的长度,当Payload len为0~125时,表示的值就是Payload Data的真实长度;当Payload len为126时,报文其后的2个字节形成的16bits无符号整型数的值是Payload Data的真实长度(网络字节序,需转换);当Payload len为127时,报文其后的8个字节形成的64bits无符号整型数的值是Payload Data的真实长度(网络字节序,需转换);

    Masking-key:掩码,当Mask为1时存在,占4字节32bit

    Payload Data:表示数据

    C++对websocket协议处理

    /**

    * @brief getWSFrameData 解析websocket的协议包,不能解决粘包半包问题

    * @param msg 待解析的数据

    * @param msgLen 待解析的数据长度

    * @param outBuf 解析完成数据

    * @return

    */int unPackingWSFrameData(char *msg,int msgLen,std::vector &outBuf){//报文长度一定大于2字节,对于小于的,做返回处理if(msgLen < 2)

    {return -3;

    }uint8_t opcode_ = 0;uint8_t mask_ = 0;uint8_t masking_key_[4] = {0,0,0,0};uint64_t payload_length_ = 0;int pos = 0;//Opcodeopcode_ = msg[pos] & 0x0f;

    pos++;//MASKmask_ = (unsigned char)msg[pos] >> 7;//Payload lengthpayload_length_ = msg[pos] & 0x7f;

    pos++;if(payload_length_ == 126)

    {uint16_t length = 0;memcpy(&length, msg + pos, 2);

    pos += 2;

    payload_length_ = ntohs(length);

    }else if(payload_length_ == 127)

    {uint32_t length = 0;memcpy(&length, msg + pos, 8);

    pos += 8;

    payload_length_ = ntohl(length);

    }//Masking-keyif(mask_ == 1)

    {for(int i = 0; i < 4; i++)

    {

    masking_key_[i] = msg[pos + i];

    }

    pos += 4;

    }//取出消息数据if (msgLen >= pos + payload_length_ )

    {

    outBuf.clear();if(mask_ != 1)

    {char* dataBegin = msg + pos;

    outBuf.insert(outBuf.begin(), dataBegin, dataBegin+payload_length_);

    }else{for(uint i = 0; i < payload_length_; i++)

    {int j = i % 4;

    outBuf.push_back(msg[pos + i] ^ masking_key_[j]);

    }

    }

    }else{//此时包长小于报文中记录的包长return -2;

    }//断开连接类型数据包if ((int)opcode_ == 0x8)return -1;return 0;

    }

    以上函数即实现了对收到websocket数据的解析,返回结果为:vectoroutput;

    通常会在函数外面对此进行转换为char*,方便我们使用,见下:

    vectoroutput;char* out = &output[0];

    当然,现在的解析还不是完美的解决方法,因为在实际的使用当中,会存在接收的包粘包,半包等等问题,而以上函数只能解决收到包正好是一个完整的包的情况;具体解决粘包半包问题,留待下次博客吧!

    参考资料:后台私信“资料”送

    结尾:只为记录,只为分享! 愿所写能对你有所帮助。不忘记点个赞,谢谢~

    后台私信可以领取 内容包括:C/C++,Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体, WebRTC ,CDN,P2P,K8S,Docker,Golang, TCP/IP,MTK , 嵌入式 , 协程,DPDK等等 。

    展开全文
  • websocket遇到的问题以及解决方法

    千次阅读 2020-12-21 04:54:20
    一、前言在本文中我使用的websocket框架是FaceBook提供的SocketRocket框架,在此不再为此进行过多的介绍,网上websocket介绍很全,如:SRWebSocket源码浅析,还有理解websocket的文章:WebSocket原理等。本文着重...
  • 解决办法:只需要 add_header Access-Control-Allow-Origin 一次就! http { ...... add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Headers X-Requested-With; add_header ...
  • WebSocket,我已准备好了!

    千次阅读 2016-09-07 11:44:54
    ActiveX技术逐渐远去,Html5来了,WebSocket可以开始发威了,错,就是你了,我已准备好。 Delphi的IdHttpServer做服务端,已经测试成功。握手、发送消息都问题。
  • 解决websocket

    2018-04-12 17:28:39
    Simple Web Sockets for Unity WebGL 在assetstore中下载,代替websocket-sharp.dll
  • WebSocket是HTML5出的东西 也就是说HTTP协议没有变化 但HTTP是不支持持久连接的(长连接,循环连接的不算)
  • websocket之一:准备工作

    千次阅读 2014-09-01 15:20:48
    websocket之一:准备工作,有需要的朋友可以参考下。 最近做个项目,涉及管理前端不少设备,当然真正的管理是在平台上,那么就需要平台与前端通信,项目组选择websocket协议,搞过,摸索着搞,顺便记点吧,由于...
  • 该提示在Lodop旧版本中是: 提示"WebSocket没准备好,点确定继续",提示“C-Lodop没准备好”,新版本修改了该提示的描述“网页还下载完毕,请稍等一下再操作.”,让问题更解释更直观。 问题原因:调用C-Lodop云...
  • ,去官网 GitHub找了一个:点击访问 , 拿到了加密算法文件,按照上面说明,分别生成:mqttclientId、mqttUsername、mqttPasswrod、port端口号、url域名,就可以实现链接啦! 4.1 为了简单实用,降低耦合,我一度...
  • jmeter websocket测试

    2017-10-26 15:19:42
    JMeterWebSocketSampler-1.0.2-SNAPSHOT.jar 这插件依赖一下几个jar包 ...我们准备好这些jar包后,讲它们拷贝到Jmeter目录的\lib\ext\目录下。 在线程组下 添加->Sampler->WebSocket Sampler,完成websocket测试
  • Jmeter实现WebSocket接口的所必须的插件包 ...2、jetty-io-9.1.2.v20140210.jar 3、jetty-util-9.1.2.v20140210.jar 4、websocket-api-9.1.1.v...我们准备好这些jar包后,将它们拷贝到Jmeter目录的\lib\ext\目录下。
  • WebSocket

    2019-04-13 10:05:44
    今日发现项目中包含websocket...WebSocket是HTML5出的东西(协议),也就是说HTTP协议没有变化,或者说关系,但HTTP是不支持持久连接的(长连接,循环连接的不算) 首先HTTP有 1.1 和 1.0 之说,也就是所谓的 kee...
  • WebSocket协议入门:WebSocket API

    万次阅读 2020-04-15 17:24:00
    点击connect按钮,服务器代码显示 点击send按钮,浏览器发送数据,服务器回送... var wsServer = 'ws://192.168.189.155:9096/';ws代表websocket的意思。 https://www.cnblogs.com/fuqiang88/p/5956363.html ...
  • 第一步,准备好自己的域名,备案等,就不啰嗦了。 第二步,到阿里云申请免费的证书服务。  (此图片来源于网络,如有侵权,请联系删除! ) 按照提示一步步进行,最后下载得到一个pem文件和一个key文件。  将文件上传...
  • 借鉴文章所用websocket 第三方是:nv-websocket-client:2.2,而这里所用的是:Java-WebSocket:1.3.0核心代码如下:public abstract class MyWebSocketService extends Service implements IWebSocket {private static ...
  • JMeter websocket依赖的jar包: JMeterWebSocketSampler-1.0.2-SNAPSHOT.jar ...以上jar包都准备好并放到Jmeter目录的\lib\ext\目录下后,重启Jmeter之后可以在sampler中看到websocket sampler这一项
  • c++服务器websocket支持

    千次阅读 2018-06-09 22:43:08
    介绍 目前公司服务器是c++ tcp的...通俗简单点讲websocket就是山寨版的tcp,它底层实现就是tcp,唯一的区别就是网络传输时websocket协议前面多了个标志它的包头信息。去掉前面这部分包头剩下的就和普通tcp一样了。 ...
  • 我见过的最好的websocket 介绍

    千次阅读 2017-08-08 16:45:19
    转载:...作者:Ovear ...来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。一、WebSocket是HTML5出的东西(协议),也就是说HTTP协议没有变化,或者说
  • Spring Websocket

    千次阅读 2018-10-06 16:12:08
    spring 秉承一贯的作风,将我们的工作变得更加的简单方便,使用。使用原生的API太麻烦,而且对于不同的Web 容器拥有对于API的不同的实现,这个对于我们使用者来说十分的不友好,spring 将这些不同点进行...
  • 准备好这些jar包后,将它们拷贝到Jmeter目录的\lib\ext\目录下,启动jmeter。使用jmeter工具测试websocket接口,需要用到的相关jar包
  • Xray基于Nginx的VLESS WebSocket + TLS / XTLS一键...准备一个域名,可以A记录添加。 ,了解TLS WebSocket及Xray相关信息。 安装wget 。 安装/更新方式(此为Xray版) VLESS + Nginx + WebSocket + TLS或VLESS +
  • WebSocket原理

    2020-09-18 17:45:36
    本文主要剖析了 WebSocket 的原理,以及附上一个完整的聊天室实战 Demo (包含前端和后端,代码下载链接在文末)。 2、WebSocket 与 HTTP WebSocket 协议在2008年诞生,2011年成为国际标准。现在所有浏览器都已经...
  • websocket与http,轻松理解websocket

    万次阅读 2018-07-18 15:28:52
    WebSocket是HTML5出的东西(协议),也就是说HTTP协议没有变化,或者说关系,但HTTP是不支持持久连接的(长连接,循环连接的不算) 首先HTTP有 1.1 和 1.0 之说,也就是所谓的 keep-alive ,把多个HTTP请求...
  • WebSocket接口初体验

    千次阅读 2020-10-03 11:45:12
    本文简单首先介绍了WebSocket的基本概念和相关特点,WebSocket是一个全双工通信的协议,它支持客户端向服务端发送消息, 也支持服务端想客户端发送消息, 一次握手,可以多次发送消息。接着就是介绍了在SpringBoot中...
  • WebSocket简单应用

    2020-01-06 14:55:40
    websocket实时通知 目标 订单支付成功,系统弹窗提示订单支付成功,避免询问客户是否支付,要求客户出示支付凭证,引起客户反感 需求池 1、 订单支付成功实时通知到系统并弹窗提示。 2、 弹窗在系统页面的右下角...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 12,247
精华内容 4,898
热门标签
关键字:

websocket没准备好