WebSocket总结

Posted Harris-H

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WebSocket总结相关的知识,希望对你有一定的参考价值。

WebSocket总结

  • 基于TCP的新网络协议,实现浏览器与服务器全双工通信。

  • 在这里插入图片描述

  • 在这里插入图片描述

img

3.优点

在以前的消息推送机制中,用的都是 Ajax 轮询(polling),在特定的时间间隔由浏览器自动发出请求,将服务器的消息主动的拉回来,这种方式是非常消耗资源的,因为它本质还是http请求,而且显得非常笨拙。而WebSocket 在浏览器和服务器完成一个握手的动作,在建立连接之后,服务器可以主动传送数据给客户端,客户端也可以随时向服务器发送数据。

4.WebSocket和Socket的区别

1.WebSocket:

    1. websocket通讯的建立阶段是依赖于http协议的。最初的握手阶段是http协议,握手完成后就切换到websocket协议,并完全与http协议脱离了。
    2. 建立通讯时,也是由客户端主动发起连接请求,服务端被动监听。
    3. 通讯一旦建立连接后,通讯就是“全双工”模式了。也就是说服务端和客户端都能在任何时间自由得发送数据,非常适合服务端要主动推送实时数据的业务场景。
    4. 交互模式不再是“请求-应答”模式,完全由开发者自行设计通讯协议。
    5. 通信的数据是基于“帧(frame)”的,可以传输文本数据,也可以直接传输二进制数据,效率高。当然,开发者也就要考虑封包、拆包、编号等技术细节。

2.Socket:

    1. 服务端监听通讯,被动提供服务;客户端主动向服务端发起连接请求,建立起通讯。
    2. 每一次交互都是:客户端主动发起请求(request),服务端被动应答(response)。
    3. 服务端不能主动向客户端推送数据。
    4. 通信的数据是基于文本格式的。二进制数据(比如图片等)要利用base64等手段转换为文本后才能传输。

SpringBoot整合WebSocket

参考文章

1.导入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

2.开启WebSocket支持

@Configuration
public class WebSocketConfig {

	@Bean
	public ServerEndpointExporter serverEndpointExporter(){
		return new ServerEndpointExporter();
	}
}

3.WebSocketServer 核心类

几个常用的注解:

@OnOpen 连接建立成功调用的方法

OnClose 连接关闭调用的方法

OnMessage 收到客户端消息后调用的方法

OnError 报错时调用的方法

@Component
@ServerEndpoint("/imserver/{userId}")
public class WebSocketServer {
    	/**
	 * 连接建立成功调用的方法
	 */
	@OnOpen
	public void onOpen(Session session, @PathParam("userId") String userId) {

		this.session = session;
		this.userId = userId;

		if (webSocketMap.containsKey(userId)) {
			webSocketMap.remove(userId);
			webSocketMap.put(userId, this);
			addOnlineCount();
		} else {
			webSocketMap.put(userId, this);
			addOnlineCount();
		}

		log.info("用户" + userId + "连接,当前在线人数为:" + getOnlineCount());

		try {
			sendMessage("连接成功");
		} catch (IOException e) {
			log.error("用户:" + userId + ",网络异常,哈哈哈");
			e.printStackTrace();
		}

	}
    	/**
	 * 连接关闭调用的方法
	 */
	@OnClose
	public void onClose() {
		if (webSocketMap.containsKey(userId)) {
			webSocketMap.remove(userId);
			subOnlineCount();
		}
		log.info("用户:" + userId + "退出成功,当前在线人数为:" + getOnlineCount());

	}
    	/**
	 * 收到客户端消息后调用的方法
	 */
	@OnMessage
	public void onMessage(String message, Session session) {
		log.info("用户消息:" + userId + ",报文:" + message);
		//可以群发消息
		//消息保存到数据库、redis
		if (StringUtils.isNotBlank(message)) {
			try {
				// 解析报文
				JSONObject jsonObject = JSON.parseObject(message);
				// 追加发送人(防止串改)
				jsonObject.put("fromUserId", this.userId);
				String toUserId = jsonObject.getString("toUserId");
				if (StringUtils.isNotBlank(toUserId) && webSocketMap.containsKey(toUserId)) {
					webSocketMap.get(toUserId).sendMessage(jsonObject.toJSONString());
				}else {
					log.error("请求的userId:"+toUserId+"不在该服务器上");
				}
			} catch (IOException e) {
				e.printStackTrace();
			}

		}
	}
    	@OnError
	public void onError(Session session, Throwable error) {
		log.error("用户错误:" + this.userId + ",原因:" + error.getMessage());
		error.printStackTrace();
	}
}

4.前端界面

客户端主动发起一次请求建立WebSocket连接,双方进行一次握手即可实现全双工通信。

  • 前端发起建立WebSocket请求,会通过WebSocketServer 的@ServerEndpoint 进行访问

在这里插入图片描述

若连接建立则会先会调用客户端所写的OnOpen方法

在这里插入图片描述

服务器收到后会调用服务器端的OnOpen方法。

在这里插入图片描述

  • 通过服务器端的提供的接口来初始化Socket对象。
  • socket对象具有send方法可以给服务器端发送消息(字符串)。
<script>
    var socket;

    function openSocket() {
        if (typeof (WebSocket) == "undefined") {
            console.log("您的浏览器不支持WebSocket");
        } else {
            console.log("您的浏览器支持WebSocket");
            //实现化WebSocket对象,指定要连接的服务器地址与端口  建立连接
            //等同于socket = new WebSocket("ws://localhost:8888/xxxx/im/25");
            //var socketUrl="${request.contextPath}/im/"+$("#userId").val();
            var socketUrl = "http://localhost:8080/imserver/" + $("#userId").val();
            socketUrl = socketUrl.replace("https", "ws").replace("http", "ws");
            console.log(socketUrl);
            if (socket != null) {
                socket.close();
                socket = null;
            }
            socket = new WebSocket(socketUrl);
            //打开事件
            socket.onopen = function () {
                console.log("websocket已打开");
                //socket.send("这是来自客户端的消息" + location.href + new Date());
            };
            //获得消息事件
            socket.onmessage = function (msg) {
                console.log(msg.data);
                //发现消息进入    开始处理前端触发逻辑
            };
            //关闭事件
            socket.onclose = function () {
                console.log("websocket已关闭");
            };
            //发生了错误事件
            socket.onerror = function () {
                console.log("websocket发生了错误");
            }
        }
    }

    function sendMessage() {
        if (typeof (WebSocket) == "undefined") {
            console.log("您的浏览器不支持WebSocket");
        } else {
            console.log("您的浏览器支持WebSocket");
            console.log('{"toUserId":"' + $("#toUserId").val() + '","contentText":"' + $("#contentText").val() + '"}');
            socket.send('{"toUserId":"' + $("#toUserId").val() + '","contentText":"' + $("#contentText").val() + '"}');
        }
    }
</script>

4.WebSocket实现用户之间发送消息

  • 用户指定目标用户并发送消息 将请求传给服务器
  • 服务器调用OnMessage方法 然后解析内容然后给转发给目标用户
	/**
	 * 收到客户端消息后调用的方法
	 */
	@OnMessage
	public void onMessage(String message, Session session) {
		log.info("用户消息:" + userId + ",报文:" + message);
		//可以群发消息
		//消息保存到数据库、redis
		if (StringUtils.isNotBlank(message)) {
			try {
				// 解析报文
				JSONObject jsonObject = JSON.parseObject(message);
				// 追加发送人(防止串改)
				jsonObject.put("fromUserId", this.userId);
				String toUserId = jsonObject.getString("toUserId");
				if (StringUtils.isNotBlank(toUserId) && webSocketMap.containsKey(toUserId)) {
					webSocketMap.get(toUserId).sendMessage(jsonObject.toJSONString());
				}else {
					log.error("请求的userId:"+toUserId+"不在该服务器上");
				}
			} catch (IOException e) {
				e.printStackTrace();
			}

		}
	}

	/**
	 * 实现服务器消息主动推送
	 *
	 * @param message
	 * @throws IOException
	 */
	public void sendMessage(String message) throws IOException {
		this.session.getBasicRemote().sendText(message);
	}

目标用户接受到消息会调用前端的OnMessage方法。

           //获得消息事件
            socket.onmessage = function (msg) {
                console.log(msg.data);
                //发现消息进入    开始处理前端触发逻辑
            };

发送客户端

在这里插入图片描述

接收客户端

在这里插入图片描述

所有 J a v a _ P r o j e c t Java\\_Project Java_Project项目Github下载地址

传送门

以上是关于WebSocket总结的主要内容,如果未能解决你的问题,请参考以下文章

BootStrap有用代码片段(持续总结)

golang websocket总结(问题贴)

BootStrap实用代码片段(持续总结)

Tomcat8.0 支持的WebSocket 总结

回归 | js实用代码片段的封装与总结(持续更新中...)

查看发票组代码后的总结和有感