赞
踩
TCP/IP五层模型与OSI七层模型的协议
更多计网相关的知识可以看这篇文章【计算机网络-五层和七层模型】
WebSocket协议是基于TCP的一种新的网络协议,他是应用层的一个协议,与http协议同级别。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。
WebSocket和Http的异同点
相同点:
不同点:
WebSocket和Socket
Socket本身并不是一个协议,它工作在OSI模型会话层,是一个套接字,TCP/IP网络的API,是为了方便大家直接使用更底层协议而存在的一个抽象层。Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
WebSocket则是一个典型的应用层协议。
总结: 说白了它俩并没有直接关系
WebSocket HTTP和TCP/IP
WebSocket和HTTP一样,都是建立在TCP之上,通过TCP来传输数据
需要引入的依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
开启WebSocket支持:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.server.standard.ServerEndpointExporter; @Configuration public class WebSocketConfig { /** * 注入ServerEndpointExporter, * 这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint */ @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } }
常量类:(可要可不要)
public class WebsocketConst { /** * 消息json key:cmd */ public static final String MSG_CMD = "cmd"; /** * 消息json key:msgId */ public static final String MSG_ID = "msgId"; /** * 消息json key:msgTxt */ public static final String MSG_TXT = "msgTxt"; /** * 消息json key:userId */ public static final String MSG_USER_ID = "userId"; /** * 消息类型 heartcheck */ public static final String CMD_CHECK = "heartcheck"; /** * 消息类型 user 用户消息 */ public static final String CMD_USER = "user"; /** * 消息类型 topic 系统通知 */ public static final String CMD_TOPIC = "topic"; /** * 消息类型 email */ public static final String CMD_EMAIL = "email"; /** * 消息类型 meetingsign 会议签到 */ public static final String CMD_SIGN = "sign"; /** * 消息类型 新闻发布/取消 */ public static final String NEWS_PUBLISH = "publish"; }
主要业务实现类:
@Component @ServerEndpoint("/websocket/{userId}") //此注解相当于设置访问URL public class WebSocket { private static final Logger log = LoggerFactory.getLogger(WebSocket.class); private Session session; private String userId; /** * 缓存 webSocket连接到单机服务class中(整体方案支持集群) */ private static CopyOnWriteArraySet<WebSocket> webSockets = new CopyOnWriteArraySet<>(); private static Map<String, Session> sessionPool = new HashMap<String, Session>(); @OnOpen public void onOpen(Session session, @PathParam(value = "userId") String userId) { try { this.session = session; this.userId = userId; webSockets.add(this); sessionPool.put(userId, session); log.info("【websocket消息】有新的连接,总数为:" + webSockets.size()); } catch (Exception e) { log.error(e.getMessage()); } } @OnClose public void onClose() { try { webSockets.remove(this); sessionPool.remove(this.userId); log.info("【websocket消息】连接断开,总数为:" + webSockets.size()); } catch (Exception e) { log.error(e.getMessage()); } } /** * 服务端推送消息 * * @param userId * @param message */ public void pushMessage(String userId, String message) { Session session = sessionPool.get(userId); if (session != null && session.isOpen()) { try { log.info("【websocket消息】 单点消息:" + message); session.getAsyncRemote().sendText(message); } catch (Exception e) { log.error(e.getMessage()); } } } /** * 服务端推送消息 * @param ids * @param message */ public void pushMessage(String[] ids, String message) { for (String uid:ids) { // 如果ids的格式有问题 导致某个id为"" 直接跳出本次循环 if ("".equals(uid)) continue; Session session = sessionPool.get(uid); if (session != null && session.isOpen()) { try { log.info("【websocket消息】 单点消息:" + message); session.getAsyncRemote().sendText(message); } catch (Exception e) { log.error(e.getMessage()); } } } } /** * 服务器端推送消息 */ public void pushMessage(String message) { try { webSockets.forEach(ws -> ws.session.getAsyncRemote().sendText(message)); } catch (Exception e) { log.error(e.getMessage()); } } @OnMessage public void onMessage(String message) { //todo 现在有个定时任务刷,应该去掉 log.debug("【websocket消息】收到客户端消息:" + message); JSONObject obj = new JSONObject(); //业务类型 obj.put(WebsocketConst.MSG_CMD, WebsocketConst.CMD_CHECK); //消息内容 obj.put(WebsocketConst.MSG_TXT, "心跳响应"); for (WebSocket webSocket : webSockets) { webSocket.pushMessage(message); } } }
上面的WebSocket 类 ,你可以作为一个service看待,然后根据自己的业务需求调用里面的业务方法, 例如:可以调用里面重载的三个pushMessage方法来实现 服务层向客户端发送消息
pushMessage(String message): 向所有上线的客户端发送消息
pushMessage(String userId, String message): 指定向单个客户端发送消息
pushMessage(String[] ids, String message): 指定向多个客户端发送消息
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。