如何通过WebSocket连接服务器进行数据传输
发布时间:2025-05-21 03:05:15 发布人:远客网络
一、如何通过WebSocket连接服务器进行数据传输
WebSocket是HTML5开始提供的一种浏览器与服务器间进行全双工通讯的网络技术。在WebSocket API中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。
Cocos2d-x引擎集成libwebsockets,并在libwebsockets的客户端API基础上封装了一层易用的接口,使得引擎在C++, JS, Lua层都能方便的使用WebSocket来进行游戏网络通讯。
引擎支持最新的WebSocket Version 13。
详细代码可参考引擎目录下的/samples/Cpp/TestCpp/Classes/ExtensionsTest/NetworkTest/WebSocketTest.cpp文件。
首先需要include WebSocket的头文件。
cocos2d::network::WebSocket::Delegate定义了使用WebScocket需要监听的回调通知接口。使用WebSocket的类,需要public继承这个Delegate。
class WebSocketTestLayer: public cocos2d::Layer, public cocos2d::network::WebSocket::Delegate
virtual void onOpen(cocos2d::network::WebSocket* ws);
virtual void onMessage(cocos2d::network::WebSocket* ws, const cocos2d::network::WebSocket::Data& data);
virtual void onClose(cocos2d::network::WebSocket* ws);
virtual void onError(cocos2d::network::WebSocket* ws, const cocos2d::network::WebSocket::ErrorCode& error);
后面我们再详细介绍每个回调接口的含义。
WebSocket.org提供了一个专门用来测试WebSocket的服务器"ws://echo.websocket.org"。测试代码以链接这个服务器为例,展示如何在Cocos2d-x中使用WebSocket。
cocos2d::network::WebSocket* _wsiSendText= new network::WebSocket();
init第一个参数是delegate,设置为this,第二个参数是服务器地址。 URL中的"ws://"标识是WebSocket协议,加密的WebSocket为"wss://".
_wsiSendText->init(*this,"ws://echo.websocket.org")
在调用send发送消息之前,先来看下4个消息回调。
init会触发WebSocket链接服务器,如果成功,WebSocket就会调用onOpen,告诉调用者,客户端到服务器的通讯链路已经成功建立,可以收发消息了。
void WebSocketTestLayer::onOpen(network::WebSocket* ws)
_sendTextStatus->setString("Send Text WS was opened.");
network::WebSocket::Data对象存储客户端接收到的数据, isBinary属性用来判断数据是二进制还是文本,len说明数据长度,bytes指向数据。
void WebSocketTestLayer::onMessage(network::WebSocket* ws, const network::WebSocket::Data& data)
sprintf(times,"%d", _sendTextTimes);
std::string textStr= std::string("response text msg:")+data.bytes+","+times;
_sendTextStatus->setString(textStr.c_str());
不管是服务器主动还是被动关闭了WebSocket,客户端将收到这个请求后,需要释放WebSocket内存,并养成良好的习惯:置空指针。
void WebSocketTestLayer::onClose(network::WebSocket* ws)
客户端发送的请求,如果发生错误,就会收到onError消息,游戏针对不同的错误码,做出相应的处理。
void WebSocketTestLayer::onError(network::WebSocket* ws, const network::WebSocket::ErrorCode& error)
log("Error was fired, error code:%d", error);
sprintf(buf,"an error was fired, code:%d", error);
_sendTextStatus->setString(buf);
在init之后,我们就可以调用send接口,往服务器发送数据请求。send有文本和二进制两中模式。
_wsiSendText->send("Hello WebSocket, I'm a text message.");
发送二进制数据(多了一个len参数)
_wsiSendBinary->send((unsigned char*)buf, sizeof(buf));
这是让整个流程变得完整的关键步骤,当某个WebSocket的通讯不再使用的时候,我们必须手动关闭这个WebSocket与服务器的连接。close会触发onClose消息,而后onClose里面,我们释放内存。
详细代码可参考引擎目录下的/samples/Lua/TestLua/Resources/luaScript/ExtensionTest/WebProxyTest.lua文件。
脚本接口相对C++要简单很多,没有头文件,创建WebSocket对象使用下面的一行代码搞定。参数是服务器地址。
wsSendText= WebSocket:create("ws://echo.websocket.org")
回调函数是普通的Lua function,4个消息回调和c++的用途一致,参考上面的说明。
local function wsSendTextOpen(strData)
sendTextStatus:setString("Send Text WS was opened.")
local function wsSendTextMessage(strData)
receiveTextTimes= receiveTextTimes+ 1
local strInfo="response text msg:"..strData..","..receiveTextTimes
sendTextStatus:setString(strInfo)
local function wsSendTextClose(strData)
print("_wsiSendText websocket instance closed.")
local function wsSendTextError(strData)
print("sendText Error was fired")
Lua的消息注册不同于C++的继承& Override,有单独的接口registerScriptHandler。 registerScriptHandler第一个参数是回调函数名,第二个参数是回调类型。每一个WebSocket实例都需要绑定一次。
wsSendText:registerScriptHandler(wsSendTextOpen,cc.WEBSOCKET_OPEN)
wsSendText:registerScriptHandler(wsSendTextMessage,cc.WEBSOCKET_MESSAGE)
wsSendText:registerScriptHandler(wsSendTextClose,cc.WEBSOCKET_CLOSE)
wsSendText:registerScriptHandler(wsSendTextError,cc.WEBSOCKET_ERROR)
Lua中发送不区分文本或二进制模式,均使用下面的接口。
wsSendText:sendString("Hello WebSocket中文, I'm a text message.")
当某个WebSocket的通讯不再使用的时候,我们必须手动关闭这个WebSocket与服务器的连接,以释放服务器和客户端的资源。close会触发cc.WEBSOCKET_CLOSE消息。
详细代码可参考引擎目录下的/samples/Javascript/Shared/tests/ExtensionsTest/NetworkTest/WebSocketTest.js文件。
脚本接口相对C++要简单很多,没有头文件,创建WebSocket对象使用下面的一行代码搞定。参数是服务器地址。
this._wsiSendText= new WebSocket("ws://echo.websocket.org");
JSB中的回调函数是WebSocket实例的属性,使用匿名函数直接赋值给对应属性。可以看出JS语言的特性,让绑定回调函数更加优美。四个回调的含义,参考上面c++的描述。
this._wsiSendText.onopen= function(evt){
self._sendTextStatus.setString("Send Text WS was opened.");
this._wsiSendText.onmessage= function(evt){
var textStr="response text msg:"+evt.data+","+self._sendTextTimes;
self._sendTextStatus.setString(textStr);
this._wsiSendText.onerror= function(evt){
cc.log("sendText Error was fired");
this._wsiSendText.onclose= function(evt){
cc.log("_wsiSendText websocket instance closed.");
发送文本,无需转换,代码如下:
this._wsiSendText.send("Hello WebSocket中文, I'm a text message.");
发送二进制,测试代码中,使用_stringConvertToArray函数来转换string为二进制数据,模拟二进制的发送。 new Uint16Array创建一个16位无符号整数值的类型化数组,内容将初始化为0。然后,循环读取字符串的每一个字符的Unicode编码,并存入Uint16Array,最终得到一个二进制对象。
_stringConvertToArray:function(strData){
var arrData= new Uint16Array(strData.length);
for(var i= 0; i< strData.length; i++){
arrData[i]= strData.charCodeAt(i);
send二进制接口和send文本没有区别,区别在于传入的对象,JS内部自己知道对象是文本还是二进制数据,然后做不同的处理。
var buf="Hello WebSocket中文,\0 I'm\0 a\0 binary\0 message\0.";
var binary= this._stringConvertToArray(buf);
this._wsiSendBinary.send(binary.buffer);
当某个WebSocket的通讯不再使用的时候,我们必须手动关闭这个WebSocket与服务器的连接,以释放服务器和客户端的资源。close会触发onclose消息。
二、vue中如何使用sockjs实现与websocket进行通信
1、本文将指导您在Vue中使用SockJS实现与WebSocket通信的方法。首先,回顾Java后端如何使用SockJS和Stomp进行配置,本文将聚焦Vue前端的实现。
2、在Vue项目创建阶段,使用命令`vue create***`并选择Vuex组件。项目创建后,利用WebStorm导入并执行`npm install`。
3、项目根目录或`package.json`中的`dependencies`部分需添加SockJS依赖。创建`src/store`目录并编写`store/index.js`。`store/modules`目录内创建`index.js`和`websocket.js`文件。
4、前端实现WebSocket操作包括:初始化、发送消息、订阅与断开连接。在`store`注册`actions`以实现这些方法,并在`mutations`中具体执行。
5、关键的`WEBSOCKET_CONNECT`代码主要用于连接。完成前端的WebSocket设置后,即可在页面中调用Vuex实现通信。前后端联合启动项目,验证功能。
6、最后,简要介绍使用StompJS的一些配置设置。遵循以上步骤,您将在Vue中成功实现SockJS与WebSocket通信,完成前后端数据交互。
三、前端通讯协议:WebSocket和长轮询对比分析详解
1、长轮询概述
1995年,网景通信聘请BrendanEich在网景Navigator中实现脚本编写能力,在十天的时间里,JavaScript语言诞生了。与现代JavaScript相比,它作为一种语言的能力最初非常有限,它与浏览器的文档对象模型(DOM)交互的能力很有限。JavaScript主要用于提供有限的增强以丰富文档使用功能。例如,浏览器内表单验证和在现有文档中轻量插入动态HTML。
2、1995年,网景通信聘请BrendanEich在网景Navigator中实现脚本编写能力,在十天的时间里,JavaScript语言诞生了。与现代JavaScript相比,它作为一种语言的能力最初非常有限,它与浏览器的文档对象模型(DOM)交互的能力很有限。JavaScript主要用于提供有限的增强以丰富文档使用功能。例如,浏览器内表单验证和在现有文档中轻量插入动态HTML。
3、随着浏览器大战的升温,微软的InternetExplorer达到了第4版甚至更高版本,对最强大特性集的争夺导致微软引入了最终成为XMLHttpRequest的东西。十多年来,所有浏览器都普遍支持这一功能。
4、长轮询实际上是原始轮询技术的一种更有效的形式,向服务器发出重复请求会浪费资源,因为必须建立每个新的传入连接,必须解析HTTP头,必须执行对新数据的查询,并且必须生成和交付响应(通常不提供新数据)。然后必须关闭连接并清除所有资源,而不必为每个客户端多次重复这个过程直到新数据对于一个给定的客户端可用。长轮询是一种技术,其中服务器选择尽可能长时间地保持客户端的连接打开,仅在数据变为可用后才传递响应可用或达到超时阈值。
5、长轮询是在XMLHttpRequest的后面实现的,XMLHttpRequest几乎得到了设备的普遍支持,因此通常不需要支持进一步的后备层。但是,在必须处理异常的情况下,或者可以查询服务器以获取新数据但不支持长轮询(更不用说其他更现代的技术标准)的情况下,基本轮询有时仍然具有有限的用途,并且可以使用XMLHttpRequest或通过简单的HTML脚本标签通过JSONP。
6、长轮询在服务器上要密集得多。可靠的消息排序可能是长轮询的一个问题,因为来自同一客户端的多个HTTP请求可能同时进行。例如,如果客户端打开两个浏览器选项卡使用相同的服务器资源,并且客户端应用程序将数据持久化到本地存储(如localStorage或IndexedDb),则没有内置保证不会重复数据写了不止一次。
7、根据服务器的实现,一个客户端实例对消息接收的确认也可能导致另一个客户端实例根本没有收到预期的消息,因为服务器可能错误地认为客户端已经收到了它预期的数据。
8、大多数库都不会独立于其他传输来实现长轮询,因为一般来说,长轮询通常伴随着其他传输策略,作为后备或当长轮询不起作用时将这些传输作为后备。在2018年及以后,独立的长轮询库尤其不常见,因为面对对更现代的替代方案的广泛支持,这种技术正迅速失去相关性。下面是几种不同语言的长轮询开源库:
9、大约在2008年年中,开发人员MichaelCarter和IanHickson尤其敏锐地感受到了在实现任何真正强大的东西时使用Comet的痛苦和局限性。通过在IRC和W3C邮件列表上的合作,他们制定了一项计划,为网络上的现代实时双向通信引入新标准,因此创造了WebSocket这个名称。
10、这个想法进入了W3CHTML草案标准,不久之后,MichaelCarter写了一篇文章,将Comet社区介绍给WebSockets。2010年,GoogleChrome4是第一个全面支持WebSockets的浏览器,其他浏览器供应商在接下来的几年里也纷纷效仿。2011年,RFC6455(WebSocket协议)发布到IETF网站。
11、简而言之,WebSockets是一个建立在设备TCP/IP堆栈之上的薄传输层。其目的是为Web应用程序开发人员提供本质上尽可能接近原始的TCP通信层,同时添加一些抽象以消除某些可能存在的与Web工作方式有关的摩擦。它们还迎合了这样一个事实,即网络具有额外的安全考虑因素,必须考虑这些因素以保护消费者和服务提供商。
12、WebSocket是一种事件驱动的协议,这意味着可以将其用于真正的实时通信。与HTTP不同(必须不断地请求更新),而使用WebSockets,更新在可用时就会立即发送。
13、WebSockets保持单个持久连接打开,同时消除基于HTTP请求/响应的方法出现的延迟问题。
14、WebSockets通常不使用XMLHttpRequest,因此,每次需要从服务器获取更多信息时,都不会发送标头。这反过来又减少了发送到服务器的数据负载。
15、当连接终止时,WebSockets不会自动恢复,这是应用开发中需要自己实现的机制,也是存在许多客户端开源库的原因之一。
16、早于2011年的浏览器无法支持WebSocket连接,这个现在可以忽略不计。
17、在之前的文章中有很详细的介绍,如有兴趣可以参阅《深入学习WebSockets概念和实践》。
18、通常,WebSockets将是更好的选择。
19、长轮询在服务器上占用的资源要多得多,而WebSockets在服务器上的占用空间非常小。长轮询还需要在服务器和设备之间进行多次跳跃。并且这些网关通常对允许典型连接保持打开状态的时间有不同的看法。如果它保持打开时间太长,某些东西可能会杀死它,甚至在它正在做一些重要的事情时也是如此。
20、为什么你应该使用WebSockets构建:
21、全双工异步消息传递,换句话说,客户端和服务器都可以独立地相互传输消息。
22、WebSockets无需任何重新配置即可通过大多数防火墙。
23、良好的安全模型(基于来源的安全模型)。