百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

Web端即时通讯必备技术:WebSocket快速入门

zhezhongyun 2025-01-14 19:06 60 浏览

随着Web应用程序的不断发展,越来越多的应用需要实现实时交互和通信。然而,传统的HTTP协议只支持单向通信,即客户端向服务器发送请求并接收响应。为了解决这一限制,WebSocket技术应运而生。本文将为大家介绍即时通讯技术 WebSocket的基本原理,并且讲解一个基于WebSocket + Node.js实现简易的一对一实时聊天的案例。

一、基本概念

WebSocket是一种HTML5提供的全双工通信协议(指可以在同一时间内允许两个设备之间进行双向发送和接收数据的通信协议),用于浏览器与服务器之间的实时通信。

WebSocket基于TCP传输协议,并且复用HTTP的握手通道(基于HTTP的 "keep-alive" 机制,允许在一次TCP连接中传送多个HTTP请求和响应)。建立WebSocket连接时,客户端会向服务器发送一个HTTP请求报文,其中包含升级协议的请求头,服务器在接收到该请求后会返回一个HTTP响应报文,其中包含升级协议的响应头。在收到服务器的响应后,客户端和服务器之间的连接就会升级为WebSocket连接,此时客户端和服务器之间的通信就不再需要使用HTTP协议的请求和响应报文,而是直接进行双向数据传输。因此,可以大大减少建立和断开连接的开销,并且实现更低的延迟和更高的吞吐量。

下面是它的优点:

1、实时性:与传统的HTTP请求/响应模式不同,WebSocket允许实时双向通信,使得服务器能够主动向客户端推送数据,而不需要客户端发起请求。

2、更少的网络流量:WebSockets使用更少的网络流量,因为在连接建立后,客户端和服务器之间的通信只需要很少的开销。

3、更少的延迟:由于WebSocket允许实时通信,因此它可以大大减少通信的延迟时间。

4、更少的服务器压力:WebSocket连接保持打开状态,因此服务器不需要为每个请求创建一个新的连接。这可以减轻服务器的负载并提高性能。

5、更好的跨域支持:WebSocket具有更好的跨域支持,因为它使用标准的HTTP握手来建立连接,可以使用与HTTP相同的跨域策略。

6、可扩展性:WebSocket可以轻松扩展以支持大量并发连接,因为它使用单个TCP连接来处理多个并发请求。

7、省电:WebSocket可以通过减少网络流量和延迟来减少移动设备的能耗,因此它在移动设备上的使用非常适合。

二、快速上手

步骤说明

WebSocket技术的运用主要分为3个步骤,以下分别说明:

1、建立握手连接客户端向服务器发送一个HTTP请求,其中包含Upgrade头部,表示要升级协议到WebSocket,然后服务器发送回一个带有Upgrade头部的HTTP响应,表示同意升级。接着,客户端和服务器就建立了WebSocket连接。

(1)客户端的请求头主要内容(采用HTTP请求报文格式,并且只支持GET方法)

GET ws://127.0.0.1:57924/2.html/ws HTTP/1.1

Host: 127.0.0.1:57924

Connection: Upgrade

Upgrade: websocket

Origin: http://127.0.0.1:57924

Sec-WebSocket-Key: 2DBoIM6oiUuKvzSmZnjdCA==

说明:

*Connection: Upgrade:Connection表示连接形式,Upgrade是升级的意思

*Upgrade: websocket:表示要升级为websocket协议

(2)服务端的响应头内容

HTTP/1.1 101 Switching Protocols

Upgrade: websocket

Connection: Upgrade

Sec-WebSocket-Accept: 85fqPOwals3GjAFetTkCD04AfE4=

说明:返回状态代码101表示协议已切换,完成协议升级。

2、数据传输:建立WebSocket连接之后,客户端和服务器之间可以互相发送消息。WebSocket采用帧的形式进行数据传输,一个帧包含一个或多个数据片段。帧头部包含了帧的元信息,比如数据是否被分片、数据类型等信息。接收方会将关联的帧重新组装成完整的消息。

3、关闭连接:当不再需要连接时进行时,需要关闭的一方通过 ws.close() 方法进行关闭,该方法会发送一个包含关闭码的帧。接收到关闭码后,另一方也会发送一个带有关闭码的响应帧,表示同意关闭连接。

简单实现例子

1、使用Node.js建立WebSocket服务器代码( 这里使用了ws库来创建WebSocket服务器)

// 引入ws库

const WebSocket = require('ws')

// 建立websocket服务器

const server = new WebSocket.Server({ port: 8080 })

// 建立一个空的数据集合users

let users = new Set()

let count = 0

server.on('connection', function (ws) {

/* 每当有新用户连接了该WebSocket服务器,就会建立一个持久化的连接

并触发该函数,除非一方发送关闭帧或发生网络故障才会导致连接中断 */

// ws为当下连接的用户对象,这里把用户信息收集至users集合中

users.add(ws)

//统计进来的用户数

count++

console.log(count + '名用户连接了')

ws.on('message', function (message) {

/* 接收当下用户ws在客户端发送的消息之后,就会触发该函数,

形参message就是发来的信息,此时是二进制的数据 */

users.forEach(function (user) {

// 遍历所有用户,给非自己的其他用户发送消息

if (user !== ws) {

user.send(message.toString())

}

})

})

})

说明:

(1)当建立了一个WebSocket长连接后,会触发server.on('connection',连接函数)的连接函数,参数ws就表示当下的用户,并用users集合来收集用户;

(2)在连接函数里放入 ws.on('message', 消息函数),当该ws用户在客户端发送了消息,就会触发消息函数,形参message是二进制格式的消息;

(3)在消息函数里遍历users集合,给非自身的用户都发送当下ws用户发来的消息。

2、前端简易代码

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

ws.onopen = function () {

console.log('与服务器建立了websocket连接')

ws.send('hello') // 建立连接后,立马给服务器发送字符串信息

}

ws.onmessage = function (event) {

console.log('接收到服务端发送的其他用户的消息')

console.log('打印数据' + event.data)

}

说明:

(1)WebSocket是由HTML5提供的技术,所以此处可以直接new WebSocket创建一个连接,连接的协议要改为ws,端口号与服务器建立的要对应;

(2)当建立了连接就会触发ws.onopen事件函数,当接收消息就会触发ws.onmessage事件函数。

三、WebSocket + Node.js实现一对一聊天室

讲到这里大家应该已经了解了WebSocket快速实现的方式,下面我们就为大家讲解如何使用 WebSocket + Node.js 技术来实现简易版的一对一聊天室效果。

前端代码

1、HTML+CSS代码

<style>

#box {

width: 400px;

height: 200px;

overflow-y: scroll;

padding: 10px;

margin-bottom: 20px;

border: 1px solid rgb(156, 152, 152);

background-color: #f8f4f4;

}

/* 放置聊天信息的div,为了消息有左右展示的效率设置了display:flex */

#chat-window {

display: flex;

flex-direction: column;

}

#chat-window > div {

flex-grow: 1;

padding: 5px;

max-width: 70%;

}

#chat-window > div > div {

text-align: left;

word-wrap: break-word;

padding: 5px;

border-radius: 5px;

box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.1);

}

#chat-window > div > span {

font-size: 12px;

color: #aaa6a6;

}

/* 收到对方发来的消息会动态生成类目为left-message的div标签,并设置左侧展示 */

.left-message {

align-self: flex-start;

}


/* 自己发送消息会动态生成类目为right-message的div标签,并设置右侧展示 */

.right-message {

text-align: right;

align-self: flex-end;

}

.left-message div {

background-color: #fff;

}

.right-message div {

background-color: #4dc86f;

}

</style>

<body>

<h3>一对一聊天室</h3>

<div id="box">

<div id="chat-window"></div>

</div>

<input type="text" id="message" placeholder="输入消息" />

<button id="send">发送</button> <button id="close">关闭聊天</button>

</body>

说明:

(1)有新的聊天信息会创建新的dom,放入id为"chat-window"的div里,之所以外面还要包裹一个"box"是考虑消息条数过多时,要生成滚动条的效果,所以"box”div设置了固定高度和overflow-y: scroll样式;

(2)聊天效果区分了对方和自己发的消息,模仿一般聊天效果,自己信息会显示右侧,故类名为right-message,对方消息的div标签则类名是left-message,设置弹性盒子,并给自身设置align-self样式来实现左右效果。

页面效果:

2、JS代码

<script>

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

const sendBtn = document.getElementById('send')

const closeBtn = document.getElementById('close')

const messageInput = document.getElementById('message')

const chatWindow = document.getElementById('chat-window')

const box = document.getElementById('box')

ws.onopen = function (event) {

console.log('连接成功')

})


// 点击发送按钮时,在点击事件里使用ws.send()传我的消息给服务器

sendBtn.onclick = function (event) {

const message = messageInput.value

ws.send(message)

messageInput.value = ''

chatWindow.innerHTML += `<div class="right-message"><span>我</span><div>${message}</div></div>`

box.scrollTop = box.scrollHeight

}


// 给ws绑定message事件,当服务器接收对方发送的消息并传给我时会触发,event.data就是对方的消息内容

ws.onmessage = function (event) {

const message = event.data

chatWindow.innerHTML += `<div class="left-message"><span>对方</span><div>${message}</div></div>`

box.scrollTop = box.scrollHeight

}


// 点击关闭聊天,将中断连接,我再发送信息,对方将不能收到

closeBtn.onclick = function () {

ws.close()

}

</script>

说明:

(1)首先通过new WebSocket(服务器地址) 进行WebSocket连接,然后创建ws.onopen事件函数,在函数里验证是否连接成功;

(2)给发送按钮添加点击事件,事件函数里要获取发送的消息值,然后ws.send()方法把消息传递给服务器,同时创建dom插入页面,展示我发送的消息;

(3)给ws绑定message事件,这样我就能实时接收对方发送给服务器,服务器再传递给我的消息,获取消息信息,创建dom插入页面当中;

(4)给关闭聊天按钮添加了点击事件,点击关闭将中断该用户的WebSocket连接。

后端Node.js代码

const WebSocket = require('ws')

const server = new WebSocket.Server({ port: 8080 })

let users = new Set()

// 创建连接事件函数

server.on('connection', (ws) => {

users.add(ws)


// 创建接收客户端消息的事件函数

ws.on('message', (message) => {

// 此时消息message为二进制格式,需要转成字符串

message = message.toString()

users.forEach(function (user) {

if (user !== ws) {

user.send(message)

}

})

})

ws.on('close', () => {

users.delete(ws)

})

})

该后端代码和上面的建议案例基本一致,故不再说明。

网页效果展示

启动WebSocket服务器后,打开两个客户端窗口,分别输入文字,实现实时沟通效果。

关闭实时聊天后,终止连接,再次发送信息,对方无法收到效果。

总结

WebSocket技术是一种能够实现全双工通信的协议,它使得客户端和服务器能够建立持久性连接并实现实时的数据传输和交互,从而成为了实现即时通讯的一种重要手段。本文简要介绍了WebSocket技术的基本概念和简单实现,但要想更好地应用该技术,需要进行更多的配置和学习。如果大家对WebSocket技术感兴趣,可以再做进一步的深入研究和学习。

相关推荐

Flutter TextField 边框样式以及提示文本

题记——执剑天涯,从你的点滴积累开始,所及之处,必精益求精。1引言1.1情景一一个文本框默认情况下可编辑(允许输入文本的情况)获取焦点(正在输入文本)下,会有默认的一个下划线,这个下划线的颜...

让最懂产品的人成为销售员 亿家净水试水“微分销”

国内领先的净水设备服务供应商亿家净水开始试水“微分销”,借助第三方微分销平台——有赞建立的亿家净水微商城近日已经开通。根据规划,下一步将把公司300多名员工以及遍布全国的6000多名安装服务工程师纳入...

案例分享丨各品牌软水机和中央净水机的旁通阀介绍、区分辨认和使

案例:前几天接到一个浙江的客户反馈,他说凯优的软水机安装后加的盐,使用4、5年了一直没加过盐到现在盐还是那么多,客户以前以为加完盐后能管好长时间就没把软水机当回事,最近听朋友说软水机需要定期加盐客户...

一文教你Java字符串处理(String,StringBuffer,StringBuild)

前言本文篇幅较长,但都是满满的干货,请大家耐心观看,相信会有不小的收获。本人在总结的过程中也收获了很多的知识,也希望大家可以一起借鉴学习下,希望大家最后都能有所收获!再言字符串的分类在java.lan...

浏览器渲染引擎之从入门到优化实践

在当今互联网时代,浏览器扮演着人们访问网页和应用程序的主要工具。当我们在浏览网页的时候,页面的展示和交互都是依靠浏览器进行实现的。所以浏览器的表现和性能直接影响着用户的体验。为了提供快速且高效的浏览体...

NAVI S1mple准星+视角+持枪控制台设置大全 新增显示器设置

简单男孩S1mple科斯特利耶夫(AleksandrKostyliev)生日1997年10月2日准星设置cl_crosshairalpha255;cl_crosshaircolor5;cl...

2014福布斯全球名人榜:女王碧昂斯登顶 李娜85

最近,有一篇名为《浙商炮轰马云:若不改作风,5年内必倒》的文章,在网络和自媒体上流传甚广,引起广泛关注。这篇文章是怎样出炉的?针对这个问题,《浙商》杂志记者进行了调查。2014福布斯全球名人榜前20人...

美国处女河中有一条步道,全程只有25公里

美国<:articlestyle="BOX-SIZING:border-box;BORDER-BOTTOM:0px;TEXT-ALIGN:left;BORDER-LEFT:0px...

Unreal丨模块化路牌蓝图制作(路牌模型)

本期文章介绍使用虚幻蓝图制作一个模块化的路牌,先来看一下完成后的效果。如图,这些路牌全部是使用同一个蓝图制作的资产。1素材准备基础的路牌模型我使用的是虚幻商城中的资产“FreewayProps”。然...

神奇白Tee加减法,1+1&gt;2(equal tee是什么管件)

来源:时尚芭莎说到炎炎夏日,除了空调、冰棍、西瓜、网络是缺一不可的以外,衣柜里怎么能少一件白Tee呢?2"style="text-decoration:none;outline:none;c...

跟着快联电路学习PCB设计的六个过程

PADS是一种常用的PCB设计软件,作为PCB设计工程师,必须掌握熟练应用的设计工具。与AD相比,PADS在开始和设计上相对复杂,需要更多的耐心和时间。在使用PADS设计PCB的过程中,需要关注印刷板...

Allegro软件中怎么通过ROOM框来放置元器件呢?

上述我们讲解了怎么快速的将元器件放置在PCB板上,通过图6-40所示的图可以看出,器件放置的都是很零散的,不是按模块或者是按页放置的,这里给大家介绍一些,通过在原理图添加ROOM属性,然后通过ROOM...

电路设计入门-从DXP2004双闪灯电路设计开始

DXP2004!?为什么要用这么老的版本呢?因为DXP2004是最经典的版本!protel是最原始的版本,版本包括protelforDOS,protel98,protel99se;后面prte...

小幅改进 微软或启用Outlook Mail品牌

去年十月微软就对Outlook.com及相关网站进行了改版,改进了下拉菜单,使得用户能够在微软相关的服务,比如OneDrive以及OfficeOnline之间切换。不过现在看来,微软似乎准备再一次对...

将多个属性传递给 Vue 组件的几种方式

所有使用基于组件的体系结构(如Vue和React)的开发人员都知道,创建可重用组件是很困难的,而且大多数情况下,最终会通过传入大量的属性,以便从外部更容易地控制和自定义组件。这并不坏,但是传递大量属性...