前两篇文章【WebSocket刨根问底(一)】【WebSocket刨根问底(二)】我们介绍了WebSocket的一些基本理论,以及一个简单的案例,那么今天继续,我们来看一个简单的群聊的案例,来进一步了解WebSocket这个东东。

OK,开始之前,我们先来看看我们今天要实现的效果:

好了,废话不多说,我们进来看看这个东西要怎么样实现吧!

创建Web项目

这里和上文(WebSocket刨根问底(二))一样,web项目创建成功之后,还是要我们先手动添加websocket的jar包进来,添加方式如果小伙伴不懂的话可以参考我们上篇文章,这里我就不再赘述。

创建HTML页面

页面的效果效果小伙伴们刚才都看到了,我这里就直接上代码:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>ws页面</title>
  6. <script src="jquery-3.2.1.js"></script>
  7. </head>
  8. <body>
  9. <input type="text" placeholder="请输入您的昵称" id="nickname"><input type="button" value="连接" id="btnClick1">
  10. </div>
  11. <div id="resultDiv"></div>
  12. <div><input type="text" id="msg"><input type="button" value="发送" id="btnClick2" disabled="disabled"></div>
  13. <script>
  14. var webSocket;
  15. $("#btnClick2").click(function () {
  16. var msg = $("#msg").val();
  17. $("#msg").val('');
  18. webSocket.send(msg)
  19. });
  20. $("#btnClick1").click(function () {
  21. var nickname = $("#nickname").val();
  22. if(nickname==null||nickname=='') {
  23. alert("必须输入昵称");
  24. return;
  25. }
  26. $("#btnClick2").removeAttr("disabled");
  27. $(this).attr("disabled", "disabled");
  28. $("#resultDiv").append("<p>开始连接服务端!</p>");
  29. webSocket = new WebSocket("ws://localhost/myws2/"+nickname);
  30. webSocket.onerror = function (event) {
  31. $("#resultDiv").append("<p>onerror:" + event.data + "</p>");
  32. }
  33. webSocket.onopen = function (event) {
  34. $("#resultDiv").append("<p>连接成功!</p>");
  35. }
  36. webSocket.onmessage = function (event) {
  37. $("#resultDiv").append("<p>" + event.data + "</p>");
  38. }
  39. });
  40. </script>
  41. </body>
  42. </html>

关于这段HTML代码,我说如下几点:

1.一开始发送按钮处于不可用状态,必须先连接
2.连接时必须先输入昵称,如果不输入昵称则弹出提示
3.连接成功之后连接按钮处于不可点击状态而发送按钮处于可点击状态
4.在连接按钮的点击事件中初始化WebSocket对象以及WebSocket中涉及到的一些方法的初始化
5.所有的信息(连接成功,连接出错以及接收到消息)最后都显示在resultDiv中
6.连接地址是动态变化的,最后的字符是连接的用户名

OK,这里的代码都很简单,我就不一一解释了。

创建WebSocket服务端

由于我们这里要做的是群聊,所以服务端的主要功能就是接收客户端传来的消息并将之广播给所有的客户端。服务端代码如下:

  1. @ServerEndpoint("/myws2/{nickname}")
  2. public class WebSocketServer2 {
  3. private String nickname;
  4. private Session session;
  5. private static final Set<WebSocketServer2> WEB_SOCKET_SERVER_2_SET = new CopyOnWriteArraySet<WebSocketServer2>();
  6. @OnMessage
  7. public void onMessage(String message, @PathParam(value = "nickname") String nickname) throws IOException {
  8. System.out.println("收到了客户端发来的消息:" + message);
  9. sendText(nickname+"发来了:"+message);
  10. }
  11. private static void sendText(String msg) {
  12. for (WebSocketServer2 webSocketServer2 : WEB_SOCKET_SERVER_2_SET) {
  13. try {
  14. synchronized (webSocketServer2) {
  15. webSocketServer2.session.getBasicRemote().sendText(msg);
  16. }
  17. } catch (IOException e) {
  18. WEB_SOCKET_SERVER_2_SET.remove(webSocketServer2);
  19. try {
  20. webSocketServer2.session.close();
  21. } catch (IOException e1) {
  22. }
  23. sendText(webSocketServer2.nickname + "同学已经下线");
  24. }
  25. }
  26. }
  27. @OnOpen
  28. public void onOpen(Session session, @PathParam(value = "nickname") String nickname) throws IOException {
  29. this.nickname = nickname;
  30. this.session = session;
  31. WEB_SOCKET_SERVER_2_SET.add(this);
  32. sendText(nickname + "进入房间");
  33. StringBuffer sb = new StringBuffer();
  34. for (WebSocketServer2 webSocketServer2 : WEB_SOCKET_SERVER_2_SET) {
  35. sb.append(webSocketServer2.nickname).append(";");
  36. }
  37. sendText("当前房间有:"+sb.toString());
  38. }
  39. @OnClose
  40. public void onClose(Session session) throws IOException {
  41. WEB_SOCKET_SERVER_2_SET.remove(this);
  42. sendText(this.nickname+"童鞋已下线");
  43. }
  44. }

关于这个服务端我解释如下几点:

1.第一行的代码表示服务端的名字,但是名字里边有一个{nickname},表示获取服务端传递来的最后一个参数,在方法里边可以通过@PathParam来获取,这个和SpringMVC的参数注解如出一辙
2.第三行和第四行创建了两个对象,因为当客户端脸上服务端之后,一个客户端将对应一个WebSocketServer2对象,我需要将每一个客户端的有关信息保存下来,因此创建出nickname表示该对象对应的客户端的用户昵称,session表示该对象对应的客户端的session
3.第五行创建一个Set集合,该集合是static final类型的,表示不管WebSocketServer2的对象有多少个,WEB_SOCKET_SERVER_2_SET集合始终是同一个,该集合主要用来保存所有连接的客户端对应的WebSocketServer2对象
4.第30行到41行是open方法的逻辑,该方法有两个参数,第一个session,第二个nickname,nickname参数有一个注解@PathParam表示该参数的值就是连接地址里边的最后一个字符串,这个参数是可选的。在该方法里,首先将nickname和session赋值给对应的全局变量,然后将当前对象添加到set集合中,然后调用sendText方法发送一条消息,告诉所有的客户端XXX进入房间啦,最后遍历set集合中的所有用户,拿到所有用户的用户名,再告诉所有客户端当前的房间都有谁谁谁。
5.第13-28行的sendText方法是一个自定义的静态方法,该方法主要用来向所有的客户端广播消息,该方法的基本逻辑就是遍历set集合,拿到set集合中的每一个对象和每一个对象中的session,再利用session向对应的客户端发送消息,如果消息发送失败,则将该用户从集合中移除,同时告诉剩余的客户端某某人已经下线。
6.第7-10行的代码主要用来处理客户端发送来的消息,默认的String类型的参数表示客户端发送来的消息,其他的String类型参数都要加上注解才可以,我们这里第一个参数表示客户端发送来的消息,第二个参数表示发送客户端消息的用户昵称,这里收到消息之后,再利用sendText广播给所有用户。
7.第43行到47行表示当其中一个用户下线了了会回调的close方法,在这里方法里首先从集合中移除该客户端对应的WebSocketServer2对象,然后广播一条消息将该用户下线的事告诉所有人。

OK,经过以上7点的讲解,小伙伴们对服务端的代码应该是非常熟悉了吧~

好了,那我们今天的案例就先说到这里,下篇文章我们来看一个五子棋的案例,进一步学习websocket的使用。

案例下载:http://download.csdn.net/download/u012702547/9954347(由于CSDN下载现在必须要积分,不得已设置了1分,如果小伙伴没有积分,文末留言我发给你。)

关注公众号【江南一点雨】,专注于 Spring Boot+微服务以及前后端分离等全栈技术,定期视频教程分享,关注后回复 Java ,领取松哥为你精心准备的 Java 干货!

以上。

WebSocket刨根问底(三)之群聊的更多相关文章

  1. WebSocket+Java 私聊、群聊实例

    前言 之前写毕业设计的时候就想加上聊天系统,当时已经用ajax长轮询实现了一个(还不懂什么是轮询机制的,猛戳这里:https://www.cnblogs.com/hoojo/p/longPolling ...

  2. WebSocket刨根问底(四)之五子棋大战江湖

    有暇,做了个五子棋大战的小游戏送给各位小伙伴! 用到的知识点有: 1.JavaWeb基础知识(懂jsp,servlet足够) 2.JavaScript和jQuery基本用法 3.了解WebSocket ...

  3. Java Socket通信实现私聊、群聊

    前言 闲言少叙,上代码! 代码编写 server服务端 /** * 服务端 */ public class Server { private static ServerSocket server = ...

  4. Flask 实现 WebSocket 通讯---群聊和私聊

    一.WebSocket介绍 WebSocket是一种在单个TCP连接实现了服务端和客户端进行双向文本或二进制数据通信的一种通信的协议. WebSocket使得客户端和服务器之间的数据交换变得更加简单, ...

  5. 一例完整的websocket实现群聊demo

    前言 业余我都会花一些时间在tcp.http和websocket等领域的学习,现在觉得有点收获,所以把一个基于websocket的群聊功能的例子提供给大家玩玩.当然这是一个很完整的例子,包括webso ...

  6. websocket(二)--简单实现网页版群聊

    websocket可以实现服务端的消息推送,而不必在客户端轮询,大大的节省的资源,对于实时通讯来说简直是个大喜讯. 在上一篇文章中介绍了协议握手,这篇文章将通过实现简单的群聊来帮助进一步了解webso ...

  7. WebSocket群聊与单聊

    一 . WebSocket实现群聊 py文件代码 # py文件 from flask import Flask, render_template, request from geventwebsock ...

  8. websocket 实现单聊群聊 以及 握手原理+加密方式

    WebSocket 开始代码 服务端 群聊 # type:WebSocket 给变量标注类型 # websocket web + socket from geventwebsocket.server ...

  9. flask 第五章 WebSocket GeventWebsocket 单聊群聊 握手 解密 加密

    1.WebSocket 首先我们来回顾一下,我们之前用socket学习过的项目有: 1.django 2.flask 3.FTP - 文件服务 HTTP - TCP (特点): 1.一次请求,一次响应 ...

随机推荐

  1. Laravel修改验证提示信息为中文

    1.覆盖提示信息: 打开resource/lang/en/validation.php注释掉英文提示信息 $ sudo vim resource/lang/en/validation.php 将下面的 ...

  2. vue笔记-列表渲染

    用v-for把一个数组对应为一组元素 使用方法:v-for="(item,index) in items"//也可以使用of替代in { items:源数组 item:数组元素迭代 ...

  3. 关于css盒子模型和BFC的理解

    CSS盒子模型 包含元素内容(content).内边距(padding).边框(border).外边距(margin) 一般元素总宽度 = element的width+padding的左右边距+mar ...

  4. Tips_发送请求时添加一个随机数参数,让浏览器每次都重新发请求到服务器

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. Linux yun命令使用报错:File "/usr/bin/yum", line 30 except KeyboardInterrupt, e:

    原文参考:https://www.cnblogs.com/caiji/p/7891923.html 使用yum更新perl源,报错 问题出现原因: yum包管理是使用python2.x写的,将pyth ...

  6. Golang实现requests库

    Golang实现requests库 简单的封装下,方便使用,像python的requests库一样. Github地址 Github 支持 GET.POST.PUT.DELETE applicatio ...

  7. 真正的ddos防御之道,简单干脆有效!

    话说,30G 就各种发博客 BB,唉,坦白说 ,博客园团队真心没见过世面 来 各位 先看图 啥意思呢? 就是哥的 最高防御是 600G.  没错,基本对当时的游戏没啥大的影响,10秒内恢复. 因为时间 ...

  8. Linux了解知识点

    Linux知识点   1.linux系统内核最早由芬兰大学生linus Torvalds开发. 2.Linux主要用于服务器端和嵌入式两个领域. 3.Linux的特点:开放性.多用户.多任务.良好的用 ...

  9. CF F. Shovels Shop(前缀和预处理+贪心+dp)

    F. Shovels Shop time limit per test 2 seconds memory limit per test 256 megabytes input standard inp ...

  10. ABP入门系列(17)——使用ABP集成的邮件系统发送邮件

    ABP中对邮件的封装主要集成在Abp.Net.Mail和Abp.Net.Mail.Smtp命名空间下,相应源码在此. #一.Abp集成的邮件模块是如何实现的 分析可以看出主要由以下几个核心类组成: E ...