【计算机网络】 7、websocket 概念、sdk、实现

news2025/1/31 19:21:23

文章目录

  • 一、背景
  • 二、简介
  • 三、client
    • 3.1 ws 构造函数
    • 3.2 ws.readyState
    • 3.3 ws.onopen
    • 3.4 ws.onclose
    • 3.5 ws.onmessage
    • 3.6 ws.send
    • 3.7 ws.bufferedAmount
    • 3.8 ws.onerror
  • 四、server
    • 4.1 go
      • 4.1.1 apifox client
      • 4.1.2 js client
  • 五、范式

在这里插入图片描述

一、背景

已经有了 http 协议,为什么还需要 websocket 协议呢?是因为 http 只是单向的,client 向 server 获取消息。但若 server 本身有连续状态变化时,client 很难感知,此时就有如下两种解决方案:

  • client 轮训:很浪费资源(需不断打开+关闭连接),不及时
  • websocket 协议

二、简介

websocket 协议在 2008 年产生,2011 年成为国际标准,所有浏览器都支持了。是 server push 技术 之一

在这里插入图片描述
在这里插入图片描述

其特点包括:

  • 建立在 TCP 协议之上,服务器端的实现比较容易。
    在这里插入图片描述

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

    • WebSocket协议是独立的基于TCP的协议。他和HTTP的唯一关系是建立连接的握手操作的升级请求是基于HTTP服务器的。
    • WebSocket默认使用80端口进行连接,而基于TLS(RFC2818)的WebSocket连接是基于443端口的。
  • 数据格式比较轻量,性能开销小,通信高效。

  • 可以发送文本,也可以发送二进制数据。

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

  • 协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。ws://example.com:80/some/path

三、client

可在 这里 在线运行如下client 示例:

var ws = new WebSocket("wss://echo.websocket.org");

ws.onopen = function(evt) { 
  console.log("Connection open ..."); 
  ws.send("Hello WebSockets!");
};

ws.onmessage = function(evt) {
  console.log( "Received Message: " + evt.data);
  ws.close();
};

ws.onclose = function(evt) {
  console.log("Connection closed.");
};

3.1 ws 构造函数

执行如下即会使 client 就会与 server 进行连接,ws 对象的 API 详见

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

3.2 ws.readyState

返回实例对象的当前状态,共有四种。

  • CONNECTING:值为0,表示正在连接。
  • OPEN:值为1,表示连接成功,可以通信了。
  • CLOSING:值为2,表示连接正在关闭。
  • CLOSED:值为3,表示连接已经关闭,或者打开连接失败。

下面是一个示例:

switch (ws.readyState) {
  case WebSocket.CONNECTING:
    // do something
    break;
  case WebSocket.OPEN:
    // do something
    break;
  case WebSocket.CLOSING:
    // do something
    break;
  case WebSocket.CLOSED:
    // do something
    break;
  default:
    // this never happens
    break;
}

3.3 ws.onopen

指定连接成功后的回调函数:

ws.onopen = function () {
  ws.send('Hello Server!');
}

如果要指定多个回调函数,可以使用 addEventListener():

ws.addEventListener('open', function (event) {
  ws.send('Hello Server, i am callback func1!');
});
ws.addEventListener('open', function (event) {
  ws.send('Hello Server, i am callback func 2!');
});

3.4 ws.onclose

指定连接关闭后的回调函数:

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
});

3.5 ws.onmessage

ws.onmessage = function(event) {
  var data = event.data;
  // 处理数据
};
ws.addEventListener("message", function(event) {
  var data = event.data;
  // 处理数据
});

注意,服务器数据可能是文本,也可能是二进制数据(blob对象或Arraybuffer对象)。

ws.onmessage = function(event){
  if(typeof event.data === String) {
    console.log("Received data string");
  }

  if(event.data instanceof ArrayBuffer){
    var buffer = event.data;
    console.log("Received arraybuffer");
  }
}

3.6 ws.send

向 server 发数据

// 发文本
ws.send('your message');

// 发 Blob 对象
var file = document
  .querySelector('input[type="file"]')
  .files[0];
ws.send(file);

// 发 ArrayBuffer 对象
// Sending canvas ImageData as ArrayBuffer
var img = canvas_context.getImageData(0, 0, 400, 320);
var binary = new Uint8Array(img.data.length);
for (var i = 0; i < img.data.length; i++) {
  binary[i] = img.data[i];
}
ws.send(binary.buffer);

3.7 ws.bufferedAmount

表示还有多少字节的二进制数据没有发送出去。它可以用来判断发送是否结束。

var data = new ArrayBuffer(10000000);
socket.send(data);

if (socket.bufferedAmount === 0) {
  // 发送完毕
} else {
  // 发送还没结束
}

3.8 ws.onerror

报错时的回调函数

socket.onerror = function(event) {
  // handle error event
};
socket.addEventListener("error", function(event) {
  // handle error event
});

四、server

4.1 go

gorilla/websocket 库文档

package main

import (
	"fmt"
	"github.com/gorilla/websocket"
	"log"
	"net/http"
)

func main() {
	fmt.Println("Hello World")
	setupRoutes()
	log.Fatal(http.ListenAndServe(":8080", nil))
}

func setupRoutes() {
	http.HandleFunc("/", homePage)
	http.HandleFunc("/ws", wsEndpoint)
}

func homePage(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Home Page")
}

func wsEndpoint(w http.ResponseWriter, r *http.Request) {
	// We'll need to define an Upgrader, this will require a Read and Write buffer size
	var upgrader = websocket.Upgrader{
		ReadBufferSize:  1024,
		WriteBufferSize: 1024,
	}

	upgrader.CheckOrigin = func(r *http.Request) bool { return true } // 允许跨域

	// upgrade this connection to a WebSocket connection
	ws, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println(err)
	}

	log.Println("Client Connected")
	err = ws.WriteMessage(1, []byte("Hi Client!"))
	if err != nil {
		log.Println(err)
	}

	reader(ws)
}

// listen indefinitely for new messages coming through on our WebSocket connection
func reader(conn *websocket.Conn) {
	for {
		// read in a message
		messageType, p, err := conn.ReadMessage()
		if err != nil {
			log.Println(err)
			return
		}
		// print out that message for clarity
		fmt.Println(string(p))

		if err := conn.WriteMessage(messageType, p); err != nil {
			log.Println(err)
			return
		}
	}
}

4.1.1 apifox client

首先建立连接
在这里插入图片描述

然后发送数据,也可同时接收数据:

在这里插入图片描述

实际请求如下:
在这里插入图片描述

server 端打印日志如下:
在这里插入图片描述

4.1.2 js client

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Go WebSocket Tutorial</title>
  </head>
  <body>
    <h2>Hello World</h2>

    <script>
        let socket = new WebSocket("ws://127.0.0.1:8080/ws");
        console.log("Attempting Connection...");

        socket.onopen = () => {
            console.log("Successfully Connected");
            socket.send("Hi From the Client!")
        };
        
        socket.onclose = event => {
            console.log("Socket Closed Connection: ", event);
            socket.send("Client Closed!")
        };

        socket.onerror = error => {
            console.log("Socket Error: ", error);
        };

    </script>
  </body>
</html>

在 F12 可看到 日志和 ws 收发记录:

在这里插入图片描述

在这里插入图片描述

五、范式

websocket 连接的建立是纯技术的,但如何约定 client 和 server 交互则是系统设计范畴。

  • 可设计「物品提供商」的概念。其提供 goods interface{},可以上架。用户可以实现自己的 goods(如 apple、orange…)。
  • 维护 ledger(账本)记录各 订阅者需要的 goods,当收到消息时分发给各 subscribers。
  • 提供订阅、取消订阅、查看订阅内容的接口
  • 提供定制各 goods 如何被个性化处理

todo:websocket 订阅设计的源码实现

ws go 教程
websocket 介绍
ws 协议
rfc ws 协议中文翻译

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/576007.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

懂点自动化基础就要25k? 测试总监:给你15K,爱来不来

公司前段缺人&#xff0c;也面了不少测试&#xff0c;结果竟然没有一个合适的。一开始瞄准的就是中级的水准&#xff0c;也没指望来大牛&#xff0c;提供的薪资在10-25k&#xff0c;面试的人很多&#xff0c;但平均水平很让人失望。看简历很多都是3年工作经验&#xff0c;但面试…

【C++11】C++的新特性(详解)

文章目录 1.C11简介2.统一的列表初始化2.1{}初始化2.2 std::initializer_list 3.声明3.1 auto3.2 decltype3.3 nullptr 4.范围for5.STL中一些变化5.1 array5.2 forward_list容器5.3 unordered_map和unordered_set容器 1.C11简介 相比于C98/03&#xff0c;C11则带来了数量可观的…

2023年武汉市职业院校技能大赛“网络安全”竞赛任务书

2023年武汉市职业院校技能大赛“网络安全” 竞赛任务书 一、竞赛时间 总计&#xff1a;360分钟 竞赛阶段 竞赛阶段 任务阶段 竞赛任务 竞赛时间 分值 A模块 A-1 登录安全加固 180分钟 200分 A-2 本地安全策略配置 A-3 流量完整性保护 A-4 事件监控 A-5 服…

2023年电工杯B题半成品论文使用讲解

注&#xff1a;蓝色字体为说明备注解释字体&#xff0c;不能出现在大家的论文里。黑色字体为论文部分&#xff0c;大家可以根据红色字体的注记进行摘抄。该文件为半成品论文&#xff0c;即引导大家每一步做什么&#xff0c;怎么做&#xff0c;展示按着本团队的解题思路进行建模…

Integrated LogicAnalyzer v6.2 (Vivado ILA使用方法)

Chapter 1 Overview 1.1 Feature Summary&#xff08;功能摘要&#xff09; FPGA设计中的信号连接到ILA核时钟和探针输入&#xff08;图1-1&#xff09;。这些连接到探针输入的信号以设计速度进行采样&#xff0c;并使用片上块RAM&#xff08;BRAM&#xff09;进行存储…

【旅游网】前后端分离——用户管理

1、先创建数据库&#xff0c;建立用户表 2、创建后端项目&#xff0c;这里使用Springboot&#xff0c;创建好controler、mapping、pojo、service四个文件&#xff0c;在实体里创建User类 package com.example.pjtest.Pojo;public class User {public int id_u;public Strin…

SpringBoot 之 Tomcat 与 Undertow 容器性能对比

一、前言&#x1f525; 环境说明&#xff1a;Windows10 Idea2021.3.2 Jdk1.8 SpringBoot 2.3.1.RELEASE 在上一篇《SpringBoot 之配置 Undertow 容器》一文中写道&#xff1a;“Undertow 的性能和内存使用方面都要优于 Tomcat 容器”, 这一期&#xff0c;我就要给大家来求证…

受不了了,被00后卷的想辞职了

在程序员职场上&#xff0c;什么样的人最让人反感呢? 是技术不好的人吗?并不是。技术不好的同事&#xff0c;我们可以帮他。 是技术太强的人吗?也不是。技术很强的同事&#xff0c;可遇不可求&#xff0c;向他学习还来不及呢。 真正让人反感的&#xff0c;是技术平平&…

御剑WEB指纹识别系统教程,图文教程(超详细)

「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;对网络安全感兴趣的小伙伴可以关注专栏《网络安全入门到精通》 御剑WEB指纹识别 一、基本使用二、内置字典三、自定义字典四、扫描原理 御剑WEB指纹识别系…

php html转pdf wkhtmltopdf

系统CentOS7.6 1.安装 wkhtmltopdf yum install wkhtmltopdf 看别的大佬的教程这步就已经可以正常生成&#xff0c;但我这边运行脚本的时候返回了 "wkhtmltopdf: cannot connect to X server" 2.安装 Xvfb yum install Xvfb 3.运行脚本 xvfb-run --server-ar…

20220912深圳市梧桐山桃花源看植物

20220912深圳市梧桐山桃花源看植物 2023/5/27 13:27 大自然生态探索之旅第3期 明天去梧桐山看植物。有空不&#xff1f; 交通方式&#xff1a; 黄贝岭地铁站C出口坐M445到终点&#xff01; 02木荷 https://baijiahao.baidu.com/s?id1676100940201729045&wfrspider&fo…

人生苦短,我用Python。

人生苦短&#xff0c;我用Python。欢迎大家一起分享&#xff0c;你是如何入门Python的~ 方向一&#xff1a;你是如何学习/自学 Python 的&#xff1f; 偶然的机会接触到python&#xff0c;于是开始利用空闲时间学起了python。自学过2年python&#xff0c;有一些学习心得和避坑…

分布式事务的21种武器 - 6

在分布式系统中&#xff0c;事务的处理分布在不同组件、服务中&#xff0c;因此分布式事务的ACID保障面临着一些特殊难点。本系列文章介绍了21种分布式事务设计模式&#xff0c;并分析其实现原理和优缺点&#xff0c;在面对具体分布式事务问题时&#xff0c;可以选择合适的模式…

Linux——进程轮换

目录 一.进程切换 1.定义&#xff1a; 2.硬件上下文&#xff1a; 总结&#xff1a; 一.进程切换 1.定义&#xff1a; 进程切换(process switch),作为抢占式多任务的一个重要功能&#xff0c;其实质就是OS内核挂起正在运行的进程A,然后将先前被挂起的另一个进程B恢复运行。 2.硬…

天书奇谈3D服务端搭建架设教程Centos

天书奇谈3D服务端搭建架设教程Centos 大家好&#xff0c;我是艾西&#xff0c;今天给大家分享一款回合制MMORPG手游的搭建教程。也算是G 内回合制手游的第一梯队吧&#xff0c;回合制手游总会有那么一帮热爱的玩家我们话不多说直接进入正题开始操作&#xff1a; 架设准备&…

00后们劝你们不要去外包,3年外包,废了....

先说一下自己的情况&#xff0c;专科生&#xff0c;19年通过校招进入杭州某个外包软件公司&#xff0c;干了接近3年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落! 而我已经在一个企业干了3年的功…

UNIX网络编程卷一 学习笔记 第十六章 非阻塞式IO

套接字的默认状态是阻塞的&#xff0c;当发出一个不能立即完成的套接字调用时&#xff0c;进程将被投入睡眠&#xff0c;等待相应操作完成。可能阻塞的套接字调用有以下四类&#xff1a; 1.输入操作&#xff1a;包括read、readv、recv、recvfrom、recvmsg函数。如果进程对一个阻…

公司study three

ctrlwind&#xff1a;新建桌面 ctrlwin 箭头 切换桌面 WIN CTRL F4 删除桌面 mybatis-plusstreamlambda lambda遍历 存值 if (bpmBoEntityList ! null && !bpmBoEntityList.isEmpty()) {bpmBoEntityList.forEach(x -> {BpmBoEntityDTO dto new BpmBoEntityDT…

一.《HIT2台服韩服》背包遍历和物品品质潜规则

首先找背包遍历 1.通过物品数量我们入手找 2.首先CE搜索当前药品数量 3.然后消耗一瓶血药 4.CE继续搜索10,你会发现还剩下1423个结果 5.经过我们几次的筛选,最终找到几个结果 6.拿到地址后,我们用XDBG附加游戏后查看这个地址 7.随后我们在这个地址上下写入断点,通过消耗血药,就…

English Learning - L3 作业打卡 Lesson3 Day19 2023.5.23 周二

English Learning - L3 作业打卡 Lesson3 Day19 2023.5.23 周二 引言&#x1f349;句1: She also told us “you have to break some eggs to make an omelet”.成分划分弱读连读爆破语调 &#x1f349;句2: This means you have to do what is necessary to move forward.成分…