【网络进阶】WebSocket协议

news/2024/12/2 13:42:15/

文章目录

    • 1. Web实时技术的应用
    • 2. WebSocket协议介绍
      • 2.1 WebSocket的工作原理
      • 2.2 优点
      • 2.3. 使用场景
      • 2.4 实现细节
    • 3. WebSocket服务器实现
      • 3.1 客户端代码(HTML & JavaScript)
      • 3.2 服务器端代码(C++)
      • 3.3 测试结果

1. Web实时技术的应用

实时Web技术在许多应用场景中具有重要意义,它们使得用户可以立即获得最新的数据和信息,从而提高了用户体验。以下是一些实时Web技术的典型应用:

  1. 聊天和通讯:在线聊天应用、企业通讯软件以及社交网络平台都需要实时技术来实现用户间的即时通信。一些知名的聊天应用,如WhatsApp、微信、Telegram和Slack等,都采用了实时技术。

  2. 在线协作:在线文档编辑、实时画板、项目管理工具等需要多个用户同时对文档或项目进行协作。谷歌文档(Google Docs)和微软的Office 365就是在线协作的典型例子。

  3. 实时消息推送:新闻网站、博客、股票行情、天气预报等应用需要实时向用户推送最新的数据和信息。通过实时技术,用户无需手动刷新页面,就可以接收到最新的内容。

  4. 在线游戏:多人在线游戏、实时策略游戏以及虚拟现实应用都需要实时技术来保证玩家之间的交互。实时技术可以降低延迟,提高游戏的流畅性和可玩性。

  5. 物联网(IoT):实时Web技术可以用于监控和控制物联网设备。例如,智能家居系统可以实时反馈家庭设备的状态,用户可以随时控制家电设备。

  6. 实时分析:实时数据分析、数据可视化和大数据处理需要实时技术来支持。例如,网站访问统计、销售数据分析、服务器性能监控等应用需要实时显示数据。

  7. 实时音视频通信:语音通话、视频会议和直播应用需要实时技术来传输音视频数据。这些应用通常使用WebRTC这样的实时通信技术。

  8. 实时定位和导航:基于位置的服务、地图应用和交通信息系统需要实时技术来获取和更新位置数据。例如,Uber和高德地图等应用需要实时显示用户和车辆的位置。

实时Web技术在许多领域都有广泛应用,它们为用户提供了更加丰富、更加实时的网络体验。在未来,随着5G、边缘计算等技术的普及,实时Web技术将会更加普遍地应用于各种场景。

2. WebSocket协议介绍

WebSocket协议是一种基于TCP的通信协议,它提供了一种全双工、低延迟的通信方式,使得客户端和服务器之间可以进行双向实时数据交换。WebSocket协议的设计目的是为了在Web浏览器和Web服务器之间提供更高效、更实时的双向通信。

WebSocket协议与HTTP协议不同,它使用了自己独立的协议标识符“ws”(不加密)或“wss”(加密),例如:ws://example.com 或 wss://example.com。WebSocket协议最初是作为HTML5标准的一部分提出的,现在已经被广泛应用于Web应用程序、在线游戏、实时通讯等领域。

2.1 WebSocket的工作原理

  1. 建立连接:首先,客户端会向服务器发送一个HTTP请求,请求中包含“Upgrade”和“Connection”头字段,表示希望将连接升级为WebSocket。如果服务器同意升级,它会返回一个状态码为101的HTTP响应,表示连接已经升级。

  2. 数据帧:在WebSocket连接建立后,客户端和服务器可以开始发送和接收数据。数据在WebSocket中以“帧”为单位传输,每个帧都包含一个标识符、负载长度和负载数据。标识符用于指示帧的类型(例如文本、二进制数据或控制帧)。

  3. 控制帧:WebSocket协议中有一些特殊的控制帧,用于管理连接的状态。例如,“关闭”帧用于通知对方关闭连接,“Ping”帧用于检测连接是否仍然活跃,“Pong”帧用作对“Ping”帧的响应。

  4. 关闭连接:当客户端或服务器希望关闭连接时,它们会发送一个“关闭”帧。收到“关闭”帧的一方应当回应一个“关闭”帧,然后双方都可以关闭TCP连接。在某些情况下,WebSocket连接可能因为网络原因或其他问题意外断开,这种情况下并不会发送“关闭”帧。

2.2 优点

  1. 双向实时通信:WebSocket提供了全双工通信,允许客户端和服务器同时发送和接收数据,从而实现实时交互。
  2. 低延迟:与基于HTTP的轮询或长轮询等技术相比,WebSocket能够大大降低数据交换的延迟。
  3. 减少网络开销:由于WebSocket在建立连接后可以保持长连接,因此可以减少频繁建立和关闭连接导致的额外网络开销。
  4. 易于集成:WebSocket与现有的Web技术(如HTML、CSS和JavaScript)兼容,因此开发者可以在不改变现有Web应用架构的前提下轻松地将WebSocket集成进来。

2.3. 使用场景

  1. 实时消息推送:例如聊天应用、新闻推送、股票行情等。
  2. 在线游戏:例如多人在线游戏、实时策略游戏等。
  3. 即时协作:例如在线文档编辑、实时画板等。
  4. 物联网(IoT):WebSocket可以用于实时监控和控制物联网设备。
  5. 其他实时应用:任何需要实时数据交换的场景都可以考虑使用WebSocket。

2.4 实现细节

  1. 安全性:为了提高安全性,可以使用加密的WebSocket连接(wss://)。此外,建议在服务器端实施适当的认证和授权策略。
  2. 跨域问题:WebSocket允许跨域连接,但需要注意的是,服务器端应检查请求头中的“Origin”字段以防止恶意连接。
  3. 心跳检测:为了确保连接的可靠性,可以定期发送“Ping”帧进行心跳检测,以便在连接中断时及时处理。
  4. 浏览器兼容性:虽然大多数现代浏览器都支持WebSocket,但仍需注意一些较旧版本的浏览器可能不支持。在这种情况下,可以考虑使用一些库(如Socket.IO)来提供自动降级到其他传输方式的功能。

3. WebSocket服务器实现

3.1 客户端代码(HTML & JavaScript)

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>WebSocket Client</title><style>#output {border: 1px solid #ccc;padding: 10px;width: 400px;height: 200px;overflow-y: scroll;}</style>
</head>
<body><h1>WebSocket Client</h1><label for="serverAddress">Server address:</label><input type="text" id="serverAddress" value="ws://localhost"><label for="serverPort">Port:</label><input type="number" id="serverPort" value="3000"><button id="connectBtn">Connect</button><div id="output"></div><button id="clearBtn">Clear</button><br><input type="text" id="message" placeholder="Type your message..."><button id="sendBtn">Send</button><script>function getBrowserInfo() {return {userAgent: navigator.userAgent,language: navigator.language,platform: navigator.platform,vendor: navigator.vendor,};}let ws;const serverAddress = document.getElementById('serverAddress');const serverPort = document.getElementById('serverPort');const connectBtn = document.getElementById('connectBtn');const output = document.getElementById('output');const message = document.getElementById('message');const sendBtn = document.getElementById('sendBtn');const clearBtn = document.getElementById('clearBtn');clearBtn.addEventListener('click', () => {output.innerHTML = '';});function appendOutput(text) {output.innerHTML += `${text}<br>`;output.scrollTop = output.scrollHeight;}connectBtn.addEventListener('click', () => {const address = `${serverAddress.value}:${serverPort.value}`;ws = new WebSocket(address);connectBtn.disabled = true;ws.addEventListener('open', () => {appendOutput(`Connected to server at ${address}`);ws.send(JSON.stringify(getBrowserInfo()));});ws.addEventListener('message', (event) => {appendOutput(`Server: ${event.data}`);});ws.addEventListener('close', () => {appendOutput('Disconnected from server');connectBtn.disabled = false;});ws.addEventListener('error', (event) => {appendOutput('Error: ' + event.message);});});sendBtn.addEventListener('click', () => {if (ws && ws.readyState === WebSocket.OPEN) {ws.send(message.value);appendOutput(`You: ${message.value}`);message.value = '';} else {appendOutput('Please connect to the server first.');}});message.addEventListener('keyup', (event) => {if (event.key === 'Enter') {sendBtn.click();}});</script>
</body>
</html>

3.2 服务器端代码(C++)

#include <boost/asio.hpp>
#include <boost/beast.hpp>
#include <boost/beast/websocket.hpp>
#include <iostream>
#include <string>
#include <thread>
#include <nlohmann/json.hpp>namespace beast = boost::beast;
namespace http = beast::http;
namespace websocket = beast::websocket;
namespace net = boost::asio;
using tcp = net::ip::tcp;
using json = nlohmann::json;constexpr auto DEFAULT_PORT = "3000";void handleSession(websocket::stream<tcp::socket> ws) {try {ws.accept();auto remote_endpoint = ws.next_layer().socket().remote_endpoint();std::cout << "Connected to client: " << remote_endpoint << std::endl;for (;;) {beast::flat_buffer buffer;ws.read(buffer);auto message = beast::buffers_to_string(buffer.data());std::cout << "Received: " << message << std::endl;// Check if received message is browser informationtry {auto browser_info = json::parse(message);if (browser_info.contains("userAgent") && browser_info.contains("language") &&browser_info.contains("platform") && browser_info.contains("vendor")) {std::cout << "Browser Information:\n";std::cout << "  User Agent: " << browser_info["userAgent"].get<std::string>() << std::endl;std::cout << "  Language: " << browser_info["language"].get<std::string>() << std::endl;std::cout << "  Platform: " << browser_info["platform"].get<std::string>() << std::endl;std::cout << "  Vendor: " << browser_info["vendor"].get<std::string>() << std::endl;continue;}} catch (...) {// Not a valid JSON or not containing browser information}ws.text(ws.got_text());ws.write(buffer.data());}} catch (beast::system_error const &se) {if (se.code() != websocket::error::closed)std::cerr << "Error: " << se.code().message() << std::endl;} catch (std::exception const &e) {std::cerr << "Error: " << e.what() << std::endl;}
}int main(int argc, char *argv[]) {try {auto const address = net::ip::make_address("0.0.0.0");auto const port = static_cast<unsigned short>(std::atoi(argc == 2 ? argv[1] : DEFAULT_PORT));net::io_context ioc{1};tcp::acceptor acceptor{ioc, {address, port}};std::cout << "WebSocket server is listening on " << address << ":" << port << std::endl;for (;;) {tcp::socket socket{ioc};acceptor.accept(socket);std::thread{handleSession, websocket::stream<tcp::socket>{std::move(socket)}}.detach();}} catch (std::exception const &e) {std::cerr << "Error: " << e.what() << std::endl;return EXIT_FAILURE;}
}

注意如上代码中使用了Boost.Beast库来实现WebSocket和nlohmann/json的JSON库来处理JSON数据,Boost库的安装之前已经讲解过,下面说明nlohmann/json库的安装:

  1. 使用以下命令安装 wget(如果尚未安装):
sudo yum install wget
  1. 使用 wget 下载 nlohmann/json 库的单文件版本:
wget https://github.com/nlohmann/json/releases/download/v3.10.4/json.hpp

注意:请确保下载与您的代码兼容的版本。在此示例中,我下载了 3.10.4 版本。您可以在 此处 查找其他版本。

  1. 创建一个包含 nlohmann/json 的头文件的目录:
sudo mkdir -p /usr/local/include/nlohmann
  1. 将下载的 json.hpp 文件移动到刚刚创建的目录中:
sudo mv json.hpp /usr/local/include/nlohmann/

现在,nlohmann/json库已经安装在您的CentOS 7.6系统上。在C++代码中,您可以通过包含以下头文件来使用它:

#include <nlohmann/json.hpp>

在编译时,确保链接器可以找到nlohmann/json库的头文件。这通常不需要额外的编译器标志,但如果需要,您可能需要添加-I参数以指定头文件的安装路径。例如:

g++ your_code.cpp -o your_program -I/usr/local/include

3.3 测试结果

客户端:
在这里插入图片描述
服务器端:
在这里插入图片描述


http://www.ppmy.cn/news/60636.html

相关文章

CypherRat使用

cypherrat3.5 安卓远控&#xff0c;很早之前在tg下的&#xff0c;现在可能有高版本的 使用感受 图形化界面&#xff08;相比于msf&#xff09;可用于演练新场景&#xff0c;实战的话只能用xx破解版或是瑟瑟apk让人忽视风险继续安装由于国内安卓&#xff0c;部分功能失效 生成…

五种最危险的新兴网络攻击技术

SANS研究所的网络专家揭示了包括网络罪犯和民族国家行为者在内的网络攻击者正在使用的五种最危险的新兴网络攻击技术。在旧金山举行的RSA网络安全会议上&#xff0c;由SANS研究所的几位分析师组成的讨论组讨论了新兴的网络攻击战术、技术和程序&#xff0c;并提供了如何为企业做…

Python 面向对象

Python 是一种面向对象编程语言&#xff0c;支持类、对象、继承、多态等面向对象特性。下面是一些 Python 面向对象编程的基本概念和操作&#xff1a; 1. 定义类和对象 在 Python 中&#xff0c;可以使用 class 关键字定义类。类包含属性和方法&#xff0c;属性是类的数据成员…

界面控件DevExpress WPF富文本编辑器,让系统拥有Word功能(二)

DevExpress WPF控件的富文本编辑器允许开发者将文字处理功能集成到下一个WPF项目中&#xff0c;凭借其全面的文本格式选项、邮件合并以及丰富的终端用户选项集合&#xff0c;可以轻松地提供Microsoft Word功能。 DevExpress WPF拥有120个控件和库&#xff0c;将帮助您交付满足…

AMBA协议-AXI协议详解(读写时序、Outstanding、乱序传输、原子操作)

目录 1. AXI 写通道信号 1.1. 写地址通道信号 1.2. 写数据通道信号 1.3. 写response通道信号 1.5. 握手规则 1.4. AXI 写通道之间关系 2. AXI 读通道信号 2.1. 读地址通道信号 2.2. 读数据通道信号 2.3. AXI 读通道之间关系 3. AXI传输 3.1. AXI突发读传输 3.2. …

2022 gdcpc题解(10/13)

2022gdcpc 和学弟vp了一下这场&#xff0c;本来抓的数学选手咕咕了&#xff0c;只有2个人&#xff0c;打下来的感觉就是套路题和码量太大了&#xff0c;太久没写码量题导致 I I I调太久了&#xff0c;最后G没写完&#xff0c;K也没冲出来&#xff0c;感觉数学大爹在的话这K应该…

Java注解源码分析,实现自定义注解通过反射获取

Annotation 源码分析 JDK5.0 引入,可以通过反射机制动态获取&#xff0c;大量应用于java框架中 内置注解 Override 重写父类方法时 Target(ElementType.METHOD) //该注解只能作用于方法 Retention(RetentionPolicy.SOURCE) //在编译时起作用&#xff0c;静态检查 public int…

第五十章 管理镜像 - 在报告异步上使用 Dejournal 过滤器

文章目录 第五十章 管理镜像 - 在报告异步上使用 Dejournal 过滤器在报告异步上使用 Dejournal 过滤器一般镜像注意事项Mirror APIs主要故障转移成员的外部备份在镜像成员上升级 IRIS 第五十章 管理镜像 - 在报告异步上使用 Dejournal 过滤器 在报告异步上使用 Dejournal 过滤…