浅谈WebSocket

cnblogs 2024-09-12 08:39:00 阅读 65

PS:带有自己一点个人的理解

1.什么是websocket,为什么要去使用它

首先看一下[维基百科上对Websocket的定义](WebSocket - 维基百科,自由的百科全书 (wikipedia.org)),WebSocket是一种网络传输协议,可在单个TCP连接上进行全双工通信,位于OSI模型应用层应用层。

通过这个定义,其实就已经能够看出websocket的重要性了。我们一般对前后端进行交互采用http协议,但http是一种无状态的、无连接的、单向的应用层协议。因此对于C/S架构,客户端只能向服务端发送请求之后服务端才能向客户端发送数据,服务端属于被动的一方,这使得在一些高实时性要求的业务中,http要反复连接甚至不关闭,而且速度也有些慢了。

Websocket作为全双工通信的协议,中间的传输信道相当自由,不管是服务端还是客户端都能够自由发送消息,速度上便能够大大提升。

2.简单展示一下我使用Websocket的用例

前端js和后端springboot作为演示对象,这是我自己的监控操作系统信息的一个小项目,我采用的是Websocket的原生注解。

以下是部分代码演示。

首先要创建一个后端的Websocket服务器端点

<code>import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.stereotype.Component;

import org.springframework.web.socket.server.standard.ServerEndpointExporter;

@Configuration

@Component

public class WebSocketConfig {

@Bean

public ServerEndpointExporter serverEndpointExporter() {

return new ServerEndpointExporter();

}

}

然后是后端服务器的配置和相关业务的处理

import com.example.cypherserverside.service.collect.SysDataServer;

import jakarta.websocket.*;

import jakarta.websocket.server.ServerEndpoint;

import lombok.NonNull;

import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.BeansException;

import org.springframework.context.ApplicationContext;

import org.springframework.context.ApplicationContextAware;

import org.springframework.stereotype.Component;

import java.util.concurrent.*;

@Slf4j

@ServerEndpoint(value = "/ws/url")

@Component

public class WebSocketServer implements ApplicationContextAware {

//线程安全的数据结构,防止线程冲突,Session就是和前端建立连接后由DI容器自动创建的

private final static ConcurrentHashMap<String, Session> sessions = new ConcurrentHashMap<>();

private final static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

//为了获取Bean的字段

private static ApplicationContext _applicationContext;

private static SysDataServer sysDataServer;

@Override

public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {

_applicationContext = applicationContext;

//启动定时任务

startScheduledTask();

}

/**

* 开始连接

* @param session 客户端传来的session

*/

@OnOpen

public void onOpen(Session session) {

sessions.put(session.getId(), session);

session.setMaxIdleTimeout(30000);

System.out.println("连接:" + session.getId());

}

/**

* 收到客户端消息

* @param message 来自前端的消息

*/

@OnMessage

public void onMessage(String message) {

log.info("onMessage: " + message);

}

/**

* 断开连接

*/

@OnClose

public void onClose(Session session) {

for (String key : sessions.keySet()) {

if (key.equals(session.getId())) {

sessions.remove(key);

System.out.println("关闭" + session.getId());

}

}

}

/**

* 连接失败出现异常

* @param t 异常

*/

@OnError

public void onError(Throwable t) {

log.error(t.getMessage(), t);

}

/**

* 定时任务启动,两秒一发送

*/

private static void startScheduledTask(){

scheduler.scheduleAtFixedRate(()->{

sysDataServer = _applicationContext.getBean(SysDataServer.class);

//我自己的业务逻辑,获取JsonString数据然后发给前端

String systemMessage = sysDataServer.toJSONString(sysDataServer.collectData());

broadcast(systemMessage);

}, 0, 2, TimeUnit.SECONDS);

}

//发送数据

private static void broadcast(String message){

for (Session session : sessions.values()) {

session.getAsyncRemote().sendText(message);

System.out.println("已发送:" + session.getId());

}

}

}

js部分代码展示

import { ref } from 'vue';

const processes = ref([]);

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

ws.onopen = () => {

console.log('WebSocket 连接成功');

socket.send("Hello, Server!");

};

ws.onmessage = (event) => {

const data = JSON.parse(event.data);

// 处理后端数据

processes.value = data.map(process => ({

pid: process.pid,

pname: process.pName,

cpuUsage: process.processCpuUsage,

memoryUsage: process.processMemoryUsage

}));

};

ws.onclose = () => {

console.log('WebSocket 连接关闭');

};



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。