欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

WebSocket 一、编写WebSocket客户端

程序员文章站 2022-05-18 16:34:14
...

原文链接:Writing WebSocket client applications
WebSocket client应用程序通过WebSocket协议与WebSocket servers 通讯。
Note: 此功能可应用于 Web Workers。使用 Web Workers链接

步骤:

1. 创建WebSocket对象。

要使用WebSocket 协议进行通信,需要创建一个 WebSocket 对象;创建WebSocket对象的过程,会自动尝试打开与服务器的连接。

WebSocket 构造函数要求一个必要参数url与一个可选参数protocol:

WebSocket WebSocket(
  in DOMString url,
  in optional DOMString protocols
);

url:
要连接的URL; 也就是用来响应的WebSocket server的URL。
protocols 可选:
一个string值类型的协议名称 或 一个string值类型的数组。这些字符串用于指示子协议,以便单个服务器可以实现多个WebSocket子协议(例如,您可能希望一个服务器能够根据指定的协议处理不同类型的交互)。 如果您不指定协议字符串,则假定为空字符串。

构造函数可能抛出的异常:
SECURITY_ERR
正在尝试连接的端口被阻塞。

连接错误
如果尝试连接时发生错误,首先会将名为“error”的简单事件发送给WebSocket对象(从而调用它的onerror处理程序),然后将CloseEvent发送给WebSocket对象(从而调用它的onclose处理程序) 以指出连接关闭的原因。

从Firefox 11开始,通常会在Mozilla平台的控制台中收到描述性错误消息,并通过CloseEvent收到RFC 6455第7.4节中定义的结束代码。

示例
这个例子创建了一个新的WebSocket,连接到WebSocket 服务器地址是ws://www.example.com/socketserver,协议是一个自定义协议”protocolOne”(可选项)。

var exampleSocket = new WebSocket("ws://www.example.com/socketserver", "protocolOne");

返回时,exampleSocket.readyState是CONNECTING。 一旦连接准备好传输数据,readyState将变为OPEN。

如果你想打开一个连接并且对你所支持的协议很灵活,你可以指定一个协议数组:

var exampleSocket = new WebSocket("ws://www.example.com/socketserver", ["protocolOne", "protocolTwo"]);

一旦建立了连接(即readyState是OPEN),exampleSocket.protocol会告诉你服务器选择了哪个协议。

在上面的例子中,http被ws取代,同样http被wss取代。 建立WebSocket依赖于HTTP Upgrade 机制,所以当我们发送HTTP请求ws://www.example.com或wss://www.example.com给服务器,协议会自动升级(不知道翻译的对不对)
下图说明的很清楚(来源):
WebSocket 一、编写WebSocket客户端
步骤是
1,客户端(192.168.1.99:45836)发送请求到 服务器hoyo.idv.tw :80。
2,服务器根据请求的header(Upgrade: websocket),升级http协议为WebSocket并返回。
3,以上WebSocket建立后便于http没有任何关系了。之后使用WebSocket发送、接收消息都是通过socket通信(客户端 与 服务器端的连接端口与协议已改变),都是在客户端(192.168.1.99:47508)与服务器(ws://hoyo.idv.tw:1030)之间进行。
4,发送、接收消息 前后,都可以再跟进实际应用做判断:是否已认证?没认证不允许发消息?

2. 向服务器发送数据

1,建立连接后,可以通过WebSocket 对象的 send()方法发送数据。

exampleSocket.send("Here's some text that the server is urgently awaiting!");

发送的数据可以是字符串,也可以是 Blob, 或者 ArrayBuffer
Note: Firefox 11版本,只支持发送 字符串 。

2,由于建立连接是异步的并且容易失败,因此不能保证在创建WebSocket对象之后立即调用send()方法将会成功。 但至少可以确定,可以通过定义onopen处理程序来实现:只在建立连接后,才会尝试发送数据。

exampleSocket.onopen = function (event) {
  exampleSocket.send("Here's some text that the server is urgently awaiting!"); 
};

3,使用 JSON 传输对象
可以使用JSON将复杂的数据发送给服务器。 例如,聊天程序可以使用使用JSON-encapsulated(封装)数据包实现的协议与服务器交互:

// Send text to all users through the server
function sendText() {
  // Construct a msg object containing the data the server needs to process the message from the chat client.
  var msg = {
    type: "message",
    text: document.getElementById("text").value,
    id:   clientID,
    date: Date.now()
  };

  // Send the msg object as a JSON-formatted string.
  exampleSocket.send(JSON.stringify(msg));

  // Blank the text input element, ready to receive the next line of text from the user.
  document.getElementById("text").value = "";
}

4,接收服务器端的数据
考虑一下聊天客户端应用程序,它使用前面3中提及的JSON传输对象(Using JSON to transmit objects. )。 客户端可能会收到不同类型的数据包,如:

  • Login handshake
  • Message text
  • User list updates
    解释代码:
exampleSocket.onmessage = function(event) {
  var f = document.getElementById("chatbox").contentDocument;
  var text = "";
  var msg = JSON.parse(event.data);
  var time = new Date(msg.date);
  var timeStr = time.toLocaleTimeString();

  switch(msg.type) {
    case "id":
      clientID = msg.id;
      setUsername();
      break;
    case "username":
      text = "<b>User <em>" + msg.name + "</em> signed in at " + timeStr + "</b><br>";
      break;
    case "message":
      text = "(" + timeStr + ") <b>" + msg.name + "</b>: " + msg.text + "<br>";
      break;
    case "rejectusername":
      text = "<b>Your username has been set to <em>" + msg.name + "</em> because the name you chose is in use.</b><br>"
      break;
    case "userlist":
      var ul = "";
      for (i=0; i < msg.users.length; i++) {
        ul += msg.users[i] + "<br>";
      }
      document.getElementById("userlistbox").innerHTML = ul;
      break;
  }

  if (text.length) {
    f.write(text);
    document.getElementById("chatbox").contentWindow.scrollByPages(1);
  }
};

这里我们使用JSON.parse()将JSON对象转换回原始对象,然后检查并处理其内容。

5,文本数据格式
通过WebSocket连接接收的文本采用UTF-8格式。

在Gecko 9.0(Firefox 9.0 / Thunderbird 9.0 / SeaMonkey 2.6)之前,某些有效的但不是字符的UTF-8文本,会导致连接被终止。 现在Gecko已允许这些值。

3.关闭连接

使用完WebSocket 连接,可使用 WebSocket close()方法关闭连接:

exampleSocket.close();

exampleSocket.close();
在关闭连接之前,可以使用 bufferedAmount 属性来检查是否有数据尚未在网络上传输数据。

4. 安全 注意事项

不应该在混合内容环境中使用WebSocket;也就是说,不应该从使用HTTPS加载的页面 打开不安全的WebSocket连接,反之亦然。 事实上,一些浏览器明确禁止这个,包括Firefox 8和更高版本。(https=>wss、http==>ws)