websocket作为服务端收发信息的demo

本文介绍如何使用WebSocket实现前后端的实时数据传输,探讨其与传统web请求的区别,以及在Spring框架下注入服务的常见问题。提供了一个WebSocket服务端的示例代码,展示了连接建立、关闭、消息处理和错误处理的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

websocket的使用可以使前后端的数据之间进行实时通讯。普通的web程序,由客户端发出请求,由服务端接收请求,进行处理并将结果返回客户端的这么一个流程。可是如果服务端的数据变化频率比较快,客户端要想要比较实时的获得最新的服务端数据,可能需要不断的发送请求,而websoceket进行一次握手之后,浏览器和服务器之间就会建立一条通道,就可以随时进行数据传输。

websocket里面使用@Autowired注入bseries和bean的时候可能会取不到,原因是spring管理的都是单例(singleton),和 websocket (多对象)相冲突。项目启动时初始化,会初始化 websocket (非用户连接的),spring 同时会为其注入 service,该对象的 service 不是 null,被成功注入。但是,由于 spring 默认管理的是单例,所以只会注入一次 service。当新用户进入聊天时,系统又会创建一个新的 websocket 对象,这时矛盾出现了:spring 管理的都是单例,不会给第二个 websocket 对象注入 service,所以导致只要是用户连接创建的 websocket 对象,都不能再注入了。

下面是websocket作为服务端的一个demo:

@ServerEndpoint("/webSocket/{sid}")
@Slf4j
@Component
public class WebSocketServer {

	/**
	 * concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
	 */
	private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();

	/**
	 * 与某个客户端的连接会话,需要通过它来给客户端发送数据
	 */
	private Session session;

	/**
	 * 接收sid
	 */
	private String sid="";

	//存储session的map
	private static Map<String,Object> dataMap = new HashMap<String,Object>();

	/**
	 * 连接建立成功调用的方法
	 * */
	@OnOpen
	public void onOpen(Session session,@PathParam("sid") String sid) {
		this.session = session;
		//将session存起来
		dataMap.put(sid,session);
		//如果存在就先删除一个,防止重复推送消息
		for (WebSocketServer webSocket:webSocketSet) {
			if (webSocket.sid.equals(sid)) {
				webSocketSet.remove(webSocket);
			}
		}
		webSocketSet.add(this);
		this.sid=sid;

		log.info("连接已建立");
	}

	/**
	 * 连接关闭调用的方法
	 */
	@OnClose
	public void onClose() {
		webSocketSet.remove(this);
		log.info("连接已关闭");
	}

	/**
	 * 收到客户端消息后调用的方法
	 * @param message 客户端发送过来的消息*/
	@OnMessage
	public void onMessage(String message, Session session) {
		log.info("收到来"+sid+"的信息:"+message);
		String sid = getSid(session);
		if (sid == null) {
			return;
		}
		//群发消息
		for (WebSocketServer item : webSocketSet) {
			try {
				item.sendMessage(message,sid);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	public String getSid(Session session) {
		String sid = null;
		for (String key:dataMap.keySet()) {
			Session cursession = (Session) dataMap.get(key);
			if (cursession == session) {
				sid = key;
				break;
			}
		}
		return sid;
	}

	@OnError
	public void onError(Session session, Throwable error) {
		log.error("发生错误");
		error.printStackTrace();
	}
	/**
	 * 实现服务器主动推送
	 */
	public void sendMessage(String message, String sid) throws IOException {
		Session session = (Session) dataMap.get(sid);
		session.getBasicRemote().sendText(message);
	}


	/**
	 * 群发自定义消息
	 * */
	public static void sendInfo(SocketMsg socketMsg, @PathParam("sid") String sid) throws IOException {
		String message = JSONObject.toJSONString(socketMsg);
		log.info("推送消息到"+sid+",推送内容:"+message);
		for (WebSocketServer item : webSocketSet) {
			try {
				//这里可以设定只推送给这个sid的,为null则全部推送
				if(sid==null) {
					item.sendMessage(message,sid);
				}else if(item.sid.equals(sid)){
					item.sendMessage(message,sid);
				}
			} catch (IOException ignored) { }
		}
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) {
			return true;
		}
		if (o == null || getClass() != o.getClass()) {
			return false;
		}
		WebSocketServer that = (WebSocketServer) o;
		return Objects.equals(session, that.session) &&
				Objects.equals(sid, that.sid);
	}

	@Override
	public int hashCode() {
		return Objects.hash(session, sid);
	}
}

这是websocket作为服务端的其中一种写法,在连接websocket的时候,传入了一个区分用户的ID,并把用户ID存在session中,这里的session代表的是一个websocket连接,这样在服务端向前端返回数据的时候就会知道是给谁发送的信息了。
websocket的传输信息的数据类型好像只有字符串,而且在默认情况下,会有大小的一个限制。解决方式后面补上。

自己测试的时候,可以使用
websocket在线测试

来进行收发信息的测试,注意连接的地址是以 ws:// 开头的,以上面的后端代码为例,@ServerEndpoint("/webSocket/{sid}")注解需要的连接格式为:
ws://127.0.0.1:8080/webSocket/123

连接成功以后就可以收发信息了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值