WebSocket详解

WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。

WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。可以说WebSocket的出现,使得浏览器具备了实时双向通信的能力

在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。

原来为了实现推送,很多公司用的是Ajax 轮询,即按照特定的时间间隔,由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。而websocket就可以解决这些问题。

在Spring Boot中使用WebSocket

1.pom文件增加依赖

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

2.增加配置

@Configuration
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}}

3.Java代码

@Component
@ServerEndpoint("/websocket")
public class WebSocketServerController {// 收到消息调用的方法@OnMessagepublic void onMessage(String message) {System.out.println("收到的消息为 " + message);}// 建立连接调用的方法@OnOpenpublic void onOpen() {System.out.println("Client connected");}// 关闭连接调用的方法@OnClosepublic void onClose() {System.out.println("Connection closed");}// 传输消息错误调用的方法@OnErrorpublic void OnError(Throwable error) {System.out.println("Connection error");}
}

4.前端代码

<!DOCTYPE html>
<html>
<head>
<title>Testing websockets</title>
</head>
<body><div><textarea rows="3" cols="20" id="content"></textarea><br><input type="submit" value="Start" onclick="start()" /></div><div id="messages"></div><script type="text/javascript">var webSocket = new WebSocket('ws://localhost:8080/websocket');webSocket.onerror = function(event) {onError(event)};webSocket.onopen = function(event) {onOpen(event)};webSocket.onmessage = function(event) {onMessage(event)};webSocket.onclose = function(event) {onClose(event)};function onMessage(event) {document.getElementById('messages').innerHTML += '<br />' + event.data;}function onOpen(event) {document.getElementById('messages').innerHTML = 'Connection established';}function onError(event) {alert(event);}function onClose(event) {alert(event);}function start() {var text = document.getElementById('content').value;webSocket.send(text);}</script>
</body>
</html>

所以你看websocket其实很简单,前后端各写4个事件方法就行了(当然你也可以省略一些方法)

1.建立连接
2.收到消息
3.传输消息失败
4.关闭连接

事件和具体会话关联

如果事件想和具体会话关联,方法上只要加Session参数就行(4种事件类型的方法上都可加)

举个例子,直接将用户发送给服务端的话再返回给客户端

// 收到消息调用的方法
@OnMessage
public void onMessage(Session session, String message) {try {session.getBasicRemote().sendText(message);} catch (IOException e) {e.printStackTrace();}
}

传递参数

方法上加@PathParam参数即可

@Component
@ServerEndpoint("/websocket/{sid}")
public class WebSocketServerController
@OnOpen
public void onOpen(@PathParam("sid") String sid) {System.out.println("Client connected");
}

实现一个在线群聊

后端接口

@Slf4j
@Component
@ServerEndpoint("/groupChat/{sid}/{username}")
public class GroupChatController {// 保存 组id->组成员 的映射关系private static ConcurrentHashMap<String, List<Session>> groupMemberInfoMap = new ConcurrentHashMap<>();// 收到消息调用的方法,群成员发送消息@OnMessagepublic void onMessage(@PathParam("sid") String sid,@PathParam("username") String username, String message) {List<Session> sessionList = groupMemberInfoMap.get(sid);// 先一个群组内的成员发送消息sessionList.forEach(item -> {try {String text = username + ": " + message;item.getBasicRemote().sendText(text);} catch (IOException e) {e.printStackTrace();}});}// 建立连接调用的方法,群成员加入@OnOpenpublic void onOpen(Session session, @PathParam("sid") String sid) {List<Session> sessionList = groupMemberInfoMap.get(sid);if (sessionList == null) {sessionList = new ArrayList<>();groupMemberInfoMap.put(sid,sessionList);}sessionList.add(session);log.info("Connection connected");log.info("sid: {}, sessionList size: {}", sid, sessionList.size());}// 关闭连接调用的方法,群成员退出@OnClosepublic void onClose(Session session, @PathParam("sid") String sid) {List<Session> sessionList = groupMemberInfoMap.get(sid);sessionList.remove(session);log.info("Connection closed");log.info("sid: {}, sessionList size: {}", sid, sessionList.size());}// 传输消息错误调用的方法@OnErrorpublic void OnError(Throwable error) {log.info("Connection error");}
}

前端代码很简单,放github了
地址为:https://github.com/erlieStar/spring-boot-websocket

下面来看效果

注意先连接,后发送


在线开房地址:
http://www.javashitang.com:8090/

有道无术,术可成;有术无道,止于术

欢迎大家关注Java之道公众号

好文章,我在看❤️

花了20分钟,给女朋友们写了一个web版群聊程序相关推荐

  1. 女朋友过生日,我花了20分钟给她写了一个代理服务器

    女朋友说:"看你最近挺辛苦的,我送你一个礼物吧.你看看想要什么,我来准备." 我想了半天,从书到鞋子到电子产品最后到生活用品,感觉自己什么都不缺,然后和她说:"你省省钱吧 ...

  2. 花了30分钟,给女朋友们写了个最近抖音很火的3D立体动态相册

    鉴于蛮多人私信我问我要源码的(虽然源码我就贴在下面,无奈摊手.jpg), 我想可能是他们想知道这个东西是怎么写的,所以我还是把思路写出来吧 我们先看效果 效果 代码 <!doctype html ...

  3. 【云开发】10分钟零基础学会做一个快递查询微信小程序,快速掌握微信小程序开发技能(轮播图、API请求)

    大家好,我叫小秃僧 这次分享的是10分钟零基础学会做一个快递查询微信小程序,快速掌握开发微信小程序技能. 这篇文章偏基础,特别适合还没有开发过微信小程序的童鞋,一些概念和逻辑我会讲细一点,尽可能用图说 ...

  4. sand java_我在sand用java写了一个读取wifi密码的程序,该方法由主方法调用,运行没问题,效果也正常,...

    我在sand用java写了一个读取wifi密码的程序,该方法由主方法调用,运行没问题,效果也正常,就是无法连续调用,就是如果调用一次就退出然后再运行就可以,如果用完了,再主方法里选择... 我在san ...

  5. 20分钟构建属于自己的 Linux 发行版

    导读    你想要构建自己的 Linux 发行版吗?不喜欢市面上现有的Linux发行版?你认为自己可以构建一款更好的发行版?你很幸运.我要在 20 分钟里面介绍如何构建一款发行版. 是的,你没有听错, ...

  6. 我用370行代码写了一个wxPython的任务托盘程序:实用的屏幕录像机

    文章目录 1. 前言 2. 设计思路 3. 源码 4. 打包 4.1 打包成一个目录 4.2 打包成一个文件 1. 前言 最近有同学咨询如何用wx写任务托盘程序,也有同学咨询怎样创建wx的异形窗口.恰 ...

  7. Python 写了一个网页版的「P图软件」,惊呆了!

    作者 | 小欣 来源 | Python爱好者集中营 今天是开工第一天,这篇文章可以算作是虎年的第一篇干货技术类文章了,今天小编用Python做了一个网页版的"P图软件",大致的流程 ...

  8. python斗地主游戏源码_我用tkinter写的一个斗地主练习复盘python程序

    python写的斗地主模拟器使用说明,以及python的标准控件库tkinter的使用示例. http://vdisk.weibo.com/s/C5R1f8s9EVq2y 我用python写的一个斗地 ...

  9. 我给舅舅用Python写了一个订餐系统微信小程序!生意简直火爆!

    微信登录功能的实现 通过小程序的前端 配合python-flask的后端,实现登录接口的功能 在我们正式写代码之前 读一下微信小程序的官方文档. https://developers.weixin.q ...

最新文章

  1. Go 知识点(14) — Go 多协程(单个协程触发panic会导致其它所有协程挂掉,每个协程只能捕获到自己的 panic 不能捕获其它协程)
  2. 【JAVA小游戏+水果售卖系统】基于GUI界面编程的水果“人生”模拟系统
  3. TSNE 附有codechina代码
  4. centos一键清理磁盘空间_磁盘空间不够用?教你一键清理电脑重复文件
  5. PHP 多维数组搜索 PHP multi dimensional array search
  6. python 朋友圈自动回复评论_Python自动回复微信好友新年祝福
  7. ocs 2007 r2 服务体验
  8. mysql(5.6及以下)解析json
  9. Android 一个页面上下两个ListView的页面显示
  10. unity 获取鼠标点击位置_Unity中实现瓶中液体晃动的效果(从建模开始)一
  11. 利用EEPROM实现arduino的断电存储
  12. burpsuite上传截断拿shell
  13. 64位Win10 Modelsim破解及证书LICENSE.TXT无法生成解决方法
  14. python 应用程序无法正常启动 000007b_Win7应用程序无法正常启动0x000007b怎么办?...
  15. 【英语:基础高阶_全场景覆盖表达】K3.口语陈述的思维拓展
  16. Linux---查看内存型号
  17. 古希腊的对外战争,兼谈希腊罗马的军制和战斗力
  18. 按哪个键进入BIOS设置
  19. 基于ADC电压采集的锂电池电量显示方法
  20. window下vmware使用无线网卡nat的方式上网

热门文章

  1. linux看dns解析的时间,curl测试dns解析时间
  2. (王道408考研操作系统)第五章输入/输出(I/O)管理-第一节6:设备的分配和回收
  3. libjpeg(1)
  4. c++ winpcap开发(6)
  5. USACO-Section1.2 Friday the Thirteenth (简单日期处理)
  6. linux操作系统中文件系统管理--实训
  7. visual studio运行时库MT、MTd、MD、MDd 的区别
  8. ReportViewer中设置ServerReport.ReportServerCredentials属性的方法(WEB版)
  9. matlab主程序和子函数不在一个文件夹下,怎么调用?
  10. sql server 触发器应用 insert