webrtc学习笔记3
Nodejs实战
对于我们WebRTC项目而言,nodejs主要是实现信令服务器的功能,客户端和服务器端的交互我们选择websocket作为通信协议,所以以websocket的使用为主。
web客户端 websocket
WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
很多网站为了实现推送技术,所用的技术都是 Ajax 轮询。HTML5 定义的 WebSocket 协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。

当你获取 Web Socket 连接后,你可以通过 send() 方法来向服务器发送数据,并通过 onmessage 事件来接收服务器返回的数据。
创建 WebSocket 对象
var Socket = new WebSocket(url, [protocol] );
以上代码中的第一个参数 url, 指定连接的 URL。第二个参数 protocol 是可选的,指定了可接受的子协议。
WebSocket 属性

WebSocket 事件

WebSocket 方法

Nodejs服务器 websocket
如果出现一些module错误,大概率是npm和node的版本对不上,需要手动去下载,学习笔记2里面有网址
#创建package.json文件,系统会提示相关配置,也可以使用命令:
sudo npm init -y
sudo npm install nodejs-websocket



此时环境就配置好了,可以写nodejs的代码了
(1)如何创建websocket服务器,通过createServer和listen接口;
(2)如何判断有新的连接进来,createServer的回调函数判断;
(3)如何判断关闭事件,通过on("close", callback) 事件的回调函数;
(4)如何判断接收到数据,通过on("text", callkback)事件的回调函数;
(5)如何判断接收异常,通过on("error", callkback)事件的回调函数;
(6)如何主动发送数据,调用sendText
//server.js
var ws = require("nodejs-websocket")var server = ws.createServer(function (conn) {console.log("New connection")conn.on("text", function (str) { // 收到数据的响应console.log("Received "+str)conn.sendText(str.toUpperCase()+"!!!") // 发送})conn.on("close", function (code, reason) {console.log("Connection closed")})conn.on("error", function (err) { // 出错console.log("error:" + err);})
}).listen(8001)
npm install ws
const WebSocket = require('ws');// 创建 WebSocket 客户端
const ws = new WebSocket("ws://localhost:8001");// 连接成功时的回调函数
ws.on('open', function() {console.log("Connected to server");// 发送消息ws.send("hi");
});// 收到消息时的回调函数
ws.on('message', function(data) {console.log("Received from server: " + data);
});// 出错时的回调函数
ws.on('error', function(error) {console.log("WebSocket error: " + error);
});// 连接关闭时的回调函数
ws.on('close', function() {console.log("Connection closed");
});


websocket聊天室实战
框架分析
消息类型分为三种:
- enter:新人进入 (蓝色字体显示)
- message:普通聊天信息 (黑色字体显示)
- leave:有人离开 (红色字体显示)
服务器在收到某个客户端的消息(message+enter+leave),然后将其广播给所有的客户端(包括发送者)。
//webserver.js
var ws = require("nodejs-websocket");
var port = 8010;
var user = 0;// 创建一个连接
var server = ws.createServer(function (conn) {console.log("创建一个新的连接‐‐‐‐‐‐‐‐");user++;conn.nickname = "user" + user;conn.fd = "user" + user;var mes = {};mes.type = "enter";mes.data = conn.nickname + " 进来啦";broadcast(JSON.stringify(mes)); // 广播//向客户端推送消息conn.on("text", function (str) {console.log("回复 " + str);mes.type = "message";mes.data = conn.nickname + " 说: " + str;broadcast(JSON.stringify(mes));});//监听关闭连接操作conn.on("close", function (code, reason) {console.log("关闭连接");mes.type = "leave";mes.data = conn.nickname + " 离开了";broadcast(JSON.stringify(mes));});//错误处理conn.on("error", function (err) {console.log("监听到错误");console.log(err);});}).listen(port);function broadcast(str) {server.connections.forEach(function (connection) {connection.sendText(str);});
}
//webclient.html
<html><body><h1>Websocket简易聊天</h1><div id="app"><input id="sendMsg" type="text" /><button id="submitBtn">发送</button></div></body>
</html>
<script type="text/javascript">//在页面显示聊天内容function showMessage(str, type) {var div = document.createElement("div");div.innerHTML = str;if (type == "enter") {div.style.color = "blue";} else if (type == "leave") {div.style.color = "red";}document.body.appendChild(div);}//新建一个websocketvar websocket = new WebSocket("ws://192.168.150.129:8010");//打开websocket连接websocket.onopen = function () {console.log("已经连上服务器‐‐‐‐");document.getElementById("submitBtn").onclick = function () {var txt = document.getElementById("sendMsg").value;if (txt) {//向服务器发送数据websocket.send(txt);}};};//关闭连接websocket.onclose = function () {console.log("websocket close");};//接收服务器返回的数据websocket.onmessage = function (e) {var mes = JSON.parse(e.data); // json格式showMessage(mes.data, mes.type);};
</script>



信令服务器使用map管理房间
/** ----- ZeroRTCMap ----- */
var ZeroRTCMap = function () {this._entrys = new Array();this.put = function (key, value) {if (key == null || key == undefined) {return;}var index = this._getIndex(key);if (index == -1) {var entry = new Object();entry.key = key;entry.value = value;this._entrys[this._entrys.length] = entry;} else {this._entrys[index].value = value;}};this.get = function (key) {var index = this._getIndex(key);return (index != -1) ? this._entrys[index].value : null;};this.remove = function (key) {var index = this._getIndex(key);if (index != -1) {this._entrys.splice(index, 1);}};this.clear = function () {this._entrys.length = 0;};this.contains = function (key) {var index = this._getIndex(key);return (index != -1) ? true : false;};this.size = function () {return this._entrys.length;};this.getEntrys = function () {return this._entrys;};this._getIndex = function (key) {if (key == null || key == undefined) {return -1;}var _length = this._entrys.length;for (var i = 0; i < _length; i++) {var entry = this._entrys[i];if (entry == null || entry == undefined) {continue;}if (entry.key === key) {// equalreturn i;}}return -1;};
}相关文章:
webrtc学习笔记3
Nodejs实战 对于我们WebRTC项目而言,nodejs主要是实现信令服务器的功能,客户端和服务器端的交互我们选择websocket作为通信协议,所以以websocket的使用为主。 web客户端 websocket WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行…...
Transformer架构;Encoder-Decoder;Padding Mask;Sequence Mask;
目录 Transformer架构 Transformer架构的主要组成部分: 简单举例说明输入和输出: Encoder-Decoder 编码器/解码器组成 6、位置前馈网络(Position-wise Feed-Forward Networks) 7、残差连接和层归一化 10、掩码Mask 10.1 Padding Mask 10.2 Sequence Mask 为什么…...
【leetcode详解】特殊数组II : 一题代表了一类问题(前缀和思想)
前缀和的优势 给定一个数组,前缀和的特点在于,任意给出一对始末位置,能够用O(1)的时间复杂度得到始末位置之间所有元素的某种关系。 题型分析 这道题目正是“给出始末位置,检测其中元素特点”那一类,那我们就想&#…...
SQL每日一练-0814
今日SQL题难度:🌟☆☆☆☆☆☆☆☆☆ 1、题目要求 找出每个部门中薪资最高的员工显示部门ID、部门名称、员工ID、员工姓名以及对应的薪资 2、表和虚拟数据 现有两个表:Employees 和 Departments,记录了员工和部门信息。…...
Android持久化技术—文件存储
Android持久化技术—文件存储 文件存储是Android中最基本的一种数据存储方式,它不对存储的内容进行任何的格式化处理,所有数据都是原封不动地保存到文件当中的,因而它比较适合用于存储一些简单的文本数据或二进制数据。如果你想使用文件存储…...
动手学深度学习(pytorch)学习记录12-激活函数[学习记录]
激活函数 激活函数(activation function)通过计算加权和并加上偏置来确定神经元是否应该被激活, 它们将输入信号转换为输出的可微运算。 import torch import matplotlib.pyplot as plt 简单定义一个画图的函数 def graph_drawing(x_,y_…...
微服务实战系列之玩转Docker(十)
前言 我们知道Docker的“使命”是为了快速完成应用的迁移和部署。为提升它的战斗能力,Docker官方携手发布了Docker Swarm—— 一个快速完成Docker集群构建的利器。那么请先回忆一下本系列第八篇(重点compose)和第九篇(重点networ…...
Mysql(四)---增删查改(进阶)
文章目录 前言1.查询操作1.1.全列查询1.2.指定列查询1.3.列名为表达式查询1.4.查询中使用别名1.5.去重查询1.6.排序1.6.2.NULL 1.7.条件查询1.8.分页查询 2.修改3.删除 前言 上一篇博客,我们学习了一些主键的概念,并且分别创造了一些示例表,…...
SOAP @WebService WSDL
SOAP & WebService & WSDL SOAP(Simple Object Access Protocol)WebService(Web服务)WSDL(Web Services Description Language) SOAP(Simple Object Access Protocol) **是一…...
【Qt】QWidget的toolTip属性
QWidget的toolTip属性 如果一个GUI程序,界面比较复杂,按钮比较多,使用toolTip可以设置当鼠标悬停在控件上的时候,可以弹出一个提示。 API说明 setToolTip 设置 toolTip. ⿏标悬停在该 widget 上时会有提⽰说明. setToolTipDur…...
【操作系统】什么是进程?什么是线程?两者有什么区别(面试常考!!!)
什么是进程/任务(Process/Task) 当我们打开我们的电脑的任务管理器就可以看到我们的电脑正在执行的进程。 每个应用程序运行于现代操作系统之上时,操作系统会提供一种抽象,好像系统上只有这个程序在运行,所有的硬件资…...
AI -- Machine Learning
1. What is Machine Learning 1.1 Artificial Intelligence vs. Machine Learning 1.2 Relations to Other Disciplines 与其他学科的关系 1.3 Human Learning vs. Machine Learning 1.4 What is Skill in Machine Learning 什么是机器学习的技能 1.5 Two General Types of Le…...
了解交换机_1.交换机的技术发展
1.LAN的分段-单网线 最简单的网络是两台计算机通过一根网线相连: 一根网线它有很多限制,首先只能连接两台电脑,其次不能距离太远,主要因为: (1)单路网线太长会存在信号衰减;…...
ubuntu 24.04 安装 Nvidia 显卡驱动 + CUDA + cuDNN,配置 AI 深度学习训练环境,简单易懂,一看就会!
ubuntu 24.04 安装 Nvidia 显卡驱动 CUDA cuDNN,配置 AI 深度学习训练环境,简单易懂,一看就会! 1.查看本机显卡型号 lspci | grep -i nvidia输出如下: 01:00.0 3D controller: NVIDIA Corporation GM108M [GeForc…...
跟李沐学AI:目标检测的常用算法
区域神经网络R-CNN 使用启发式搜索算法来选择锚框 -> 使用预训练模型来对每个锚框抽取特征 -> 训练一个SVM对类别进行分类 -> 训练一个线性回归模型来预测边缘框偏移 锚框大小不一,如何将不同的锚框统一为一个batch? -> 兴趣区域池化层 兴趣区域(RoI…...
基于UE5和ROS2的激光雷达+深度RGBD相机小车的仿真指南(一)---UnrealCV获取深度+分割图像
前言 本系列教程旨在使用UE5配置一个具备激光雷达深度摄像机的仿真小车,并使用通过跨平台的方式进行ROS2和UE5仿真的通讯,达到小车自主导航的目的。本教程使用的环境: ubuntu 22.04 ros2 humblewindows11 UE5.4.3python8 本系列教程将涉及以…...
Java算法解析一:二分算法及其衍生出来的问题
这个算法的前提是,数组是升序排列的 算法描述: i和j是指针可以表示查找范围 m为中间值 当目标值targat比m大时,设置查找范围在m右边:i m-1 当目标值targat比m小时,设置查找范围在m左边:j m1 当targat的…...
数学建模预测类—【一元线性回归】
每日格言:行动是治愈恐惧的良药,而犹豫拖延将不断滋养恐惧. 目录 前言 一、什么是回归分析? 1.概念理解 2.分类和一般步骤 二、一元线性回归(Matlab算法) 1.利用regress函数 2、例题讲解 总结 前言 在具体讲述线性回归…...
配置更加美观的 Swagger UI
//注册Swagger服务 private static void AddSwaggerService(IServiceCollection services){services.AddSwaggerGen(opt >{opt.SwaggerDoc("Push", new OpenApiInfo{Version "v1",Title "Push API",Description "Push API 文档"…...
软件测试 - 基础(软件测试的生命周期、测试报告、bug的级别、与开发人员产生争执的调解方式)
一、软件测试的生命周期 测试贯穿软件的整个生命周期 软件测试的生命周期: 需求分析 →测试计划→ 测试设计、测试开发→ 测试执行→ 测试评估->上线->运行维护 需求分析:判断用户的需求是否合理,是否可实现 测试计划:计划项…...
SPI通信协议与菊花链模式应用解析
四线SPI通信协议与菊花链模式应用详解1. SPI接口基础1.1 四线SPI接口定义串行外设接口(SPI)是微控制器与外围IC之间最广泛使用的通信接口之一,具有同步、全双工、主从式架构特点。标准四线SPI接口包含以下信号线:SCLK(Serial Clock):时钟信号…...
AI辅助开发:让快马AI听懂你的话,智能定制专属Win11右键菜单
最近在折腾Windows 11的右键菜单,发现新系统的右键菜单虽然简洁,但很多常用功能被折叠到二级菜单里,用起来特别不方便。作为一个开发者,我经常需要快速访问各种工具,于是萌生了自己定制右键菜单的想法。 系统检测模块设…...
OpenClaw数据标注:用Qwen3-VL:30B增强飞书图像训练集
OpenClaw数据标注:用Qwen3-VL:30B增强飞书图像训练集 1. 为什么需要自动化数据标注 作为一个小型AI团队的算法工程师,我最近遇到了一个典型的数据瓶颈问题:我们需要为垂直领域的图像识别任务构建训练集,但手动标注上千张飞书聊天…...
单细胞测序数据读取实战指南:从CellRanger到Seurat对象
1. 单细胞测序数据读取入门指南 第一次接触单细胞测序数据分析时,最让人头疼的就是数据读取环节。记得我刚入门那会儿,光是理解CellRanger输出的各种文件格式就花了整整一周时间。不过别担心,今天我就把这块硬骨头啃碎了讲给你听。 单细胞测序…...
本地部署音效生成器 Moodist 并实现外部访问
Moodist 是基于 MIT 许可的开源白噪音平台,提供了超过 75 种不同的环境声音,可以帮助用户集中注意力、保持冷静或进入放松状态。它还支持持久化声音选择,用户能够自定义声音预设,分享他们的音频配置给他人,并且集成睡眠…...
从实战到原理:镜头畸变问题的深度解析与应对策略
1. 当镜头开始"说谎":工程师亲历的畸变异常事件 上周调试项目时遇到了一个诡异现象:用120度广角镜头拍摄的棋盘格图像,中间区域像被无形的手向内挤压,边缘却反常地向外膨胀。这既不是典型的桶形畸变(边缘向内…...
为什么你需要ZXPInstaller?3分钟搞定Adobe扩展安装难题
为什么你需要ZXPInstaller?3分钟搞定Adobe扩展安装难题 【免费下载链接】ZXPInstaller Open Source ZXP Installer for Adobe Extensions 项目地址: https://gitcode.com/gh_mirrors/zx/ZXPInstaller 还在为Adobe扩展插件安装而烦恼吗?每次看到.z…...
TXS0104EPWR双向电平转换器实战指南:从4通道设计到50mA高效应用
1. TXS0104EPWR双向电平转换器入门指南 第一次接触TXS0104EPWR时,我也被这个复杂的型号名称吓到了。但实际用起来才发现,这个4通道双向电平转换器简直是嵌入式开发的"翻译官"——专门解决不同电压器件之间的"语言不通"问题。想象一下…...
AI小剧场:OpenClaw+nanobot镜像多角色对话生成
AI小剧场:OpenClawnanobot镜像多角色对话生成 1. 为什么需要AI辅助剧本创作 作为一个业余编剧爱好者,我经常遇到创作瓶颈——当需要构建多角色对话场景时,很难同时兼顾不同角色的立场连贯性和语言风格差异。传统写作工具只能提供单向输出&a…...
告别重复造轮子:用快马平台高效生成ibbot机器人的通用功能模块
作为一名经常需要开发聊天机器人的开发者,我最近在做一个餐厅订座助手的项目时,发现了一个能大幅提升效率的好方法。今天就来分享一下如何利用InsCode(快马)平台快速生成ibbot的核心功能模块,避免重复造轮子的痛苦经历。 用户意图识别模块的…...
