WebSocket刨根问底(三)之群聊
前两篇文章【WebSocket刨根问底(一)】【WebSocket刨根问底(二)】我们介绍了WebSocket的一些基本理论,以及一个简单的案例,那么今天继续,我们来看一个简单的群聊的案例,来进一步了解WebSocket这个东东。
OK,开始之前,我们先来看看我们今天要实现的效果:
好了,废话不多说,我们进来看看这个东西要怎么样实现吧!
创建Web项目
这里和上文(WebSocket刨根问底(二))一样,web项目创建成功之后,还是要我们先手动添加websocket的jar包进来,添加方式如果小伙伴不懂的话可以参考我们上篇文章,这里我就不再赘述。
创建HTML页面
页面的效果效果小伙伴们刚才都看到了,我这里就直接上代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ws页面</title>
<script src="jquery-3.2.1.js"></script>
</head>
<body>
<input type="text" placeholder="请输入您的昵称" id="nickname"><input type="button" value="连接" id="btnClick1">
</div>
<div id="resultDiv"></div>
<div><input type="text" id="msg"><input type="button" value="发送" id="btnClick2" disabled="disabled"></div>
<script>
var webSocket;
$("#btnClick2").click(function () {
var msg = $("#msg").val();
$("#msg").val('');
webSocket.send(msg)
});
$("#btnClick1").click(function () {
var nickname = $("#nickname").val();
if(nickname==null||nickname=='') {
alert("必须输入昵称");
return;
}
$("#btnClick2").removeAttr("disabled");
$(this).attr("disabled", "disabled");
$("#resultDiv").append("<p>开始连接服务端!</p>");
webSocket = new WebSocket("ws://localhost/myws2/"+nickname);
webSocket.onerror = function (event) {
$("#resultDiv").append("<p>onerror:" + event.data + "</p>");
}
webSocket.onopen = function (event) {
$("#resultDiv").append("<p>连接成功!</p>");
}
webSocket.onmessage = function (event) {
$("#resultDiv").append("<p>" + event.data + "</p>");
}
});
</script>
</body>
</html>
关于这段HTML代码,我说如下几点:
1.一开始发送按钮处于不可用状态,必须先连接
2.连接时必须先输入昵称,如果不输入昵称则弹出提示
3.连接成功之后连接按钮处于不可点击状态而发送按钮处于可点击状态
4.在连接按钮的点击事件中初始化WebSocket对象以及WebSocket中涉及到的一些方法的初始化
5.所有的信息(连接成功,连接出错以及接收到消息)最后都显示在resultDiv中
6.连接地址是动态变化的,最后的字符是连接的用户名
OK,这里的代码都很简单,我就不一一解释了。
创建WebSocket服务端
由于我们这里要做的是群聊,所以服务端的主要功能就是接收客户端传来的消息并将之广播给所有的客户端。服务端代码如下:
@ServerEndpoint("/myws2/{nickname}")
public class WebSocketServer2 {
private String nickname;
private Session session;
private static final Set<WebSocketServer2> WEB_SOCKET_SERVER_2_SET = new CopyOnWriteArraySet<WebSocketServer2>();
@OnMessage
public void onMessage(String message, @PathParam(value = "nickname") String nickname) throws IOException {
System.out.println("收到了客户端发来的消息:" + message);
sendText(nickname+"发来了:"+message);
}
private static void sendText(String msg) {
for (WebSocketServer2 webSocketServer2 : WEB_SOCKET_SERVER_2_SET) {
try {
synchronized (webSocketServer2) {
webSocketServer2.session.getBasicRemote().sendText(msg);
}
} catch (IOException e) {
WEB_SOCKET_SERVER_2_SET.remove(webSocketServer2);
try {
webSocketServer2.session.close();
} catch (IOException e1) {
}
sendText(webSocketServer2.nickname + "同学已经下线");
}
}
}
@OnOpen
public void onOpen(Session session, @PathParam(value = "nickname") String nickname) throws IOException {
this.nickname = nickname;
this.session = session;
WEB_SOCKET_SERVER_2_SET.add(this);
sendText(nickname + "进入房间");
StringBuffer sb = new StringBuffer();
for (WebSocketServer2 webSocketServer2 : WEB_SOCKET_SERVER_2_SET) {
sb.append(webSocketServer2.nickname).append(";");
}
sendText("当前房间有:"+sb.toString());
}
@OnClose
public void onClose(Session session) throws IOException {
WEB_SOCKET_SERVER_2_SET.remove(this);
sendText(this.nickname+"童鞋已下线");
}
}
关于这个服务端我解释如下几点:
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刨根问底(三)之群聊的更多相关文章
- WebSocket+Java 私聊、群聊实例
前言 之前写毕业设计的时候就想加上聊天系统,当时已经用ajax长轮询实现了一个(还不懂什么是轮询机制的,猛戳这里:https://www.cnblogs.com/hoojo/p/longPolling ...
- WebSocket刨根问底(四)之五子棋大战江湖
有暇,做了个五子棋大战的小游戏送给各位小伙伴! 用到的知识点有: 1.JavaWeb基础知识(懂jsp,servlet足够) 2.JavaScript和jQuery基本用法 3.了解WebSocket ...
- Java Socket通信实现私聊、群聊
前言 闲言少叙,上代码! 代码编写 server服务端 /** * 服务端 */ public class Server { private static ServerSocket server = ...
- Flask 实现 WebSocket 通讯---群聊和私聊
一.WebSocket介绍 WebSocket是一种在单个TCP连接实现了服务端和客户端进行双向文本或二进制数据通信的一种通信的协议. WebSocket使得客户端和服务器之间的数据交换变得更加简单, ...
- 一例完整的websocket实现群聊demo
前言 业余我都会花一些时间在tcp.http和websocket等领域的学习,现在觉得有点收获,所以把一个基于websocket的群聊功能的例子提供给大家玩玩.当然这是一个很完整的例子,包括webso ...
- websocket(二)--简单实现网页版群聊
websocket可以实现服务端的消息推送,而不必在客户端轮询,大大的节省的资源,对于实时通讯来说简直是个大喜讯. 在上一篇文章中介绍了协议握手,这篇文章将通过实现简单的群聊来帮助进一步了解webso ...
- WebSocket群聊与单聊
一 . WebSocket实现群聊 py文件代码 # py文件 from flask import Flask, render_template, request from geventwebsock ...
- websocket 实现单聊群聊 以及 握手原理+加密方式
WebSocket 开始代码 服务端 群聊 # type:WebSocket 给变量标注类型 # websocket web + socket from geventwebsocket.server ...
- flask 第五章 WebSocket GeventWebsocket 单聊群聊 握手 解密 加密
1.WebSocket 首先我们来回顾一下,我们之前用socket学习过的项目有: 1.django 2.flask 3.FTP - 文件服务 HTTP - TCP (特点): 1.一次请求,一次响应 ...
随机推荐
- linux 使用技巧 screen 管理你的远程桌面的会话创建和使用
下面介绍 screen 使用的技巧教你管理远程会话 你是不是经常需要 SSH 或者 telent 远程登录到 Linux 服务器?你是不是经常为一些长时间运行的任务而头疼,比如系统备份. ftp 传 ...
- SQL Server 优化
SELECT TOP 10 [Total Cost] = ROUND(avg_total_user_cost * avg_user_impact * (user_seeks + user_scans) ...
- 解释器、环境变量、如何运行python程序、变量先定义后引用
python解释器的介绍.解释器的安装.环境变量的添加为什么加环境变量.如何调取不同的解释器版本实现多版本共存.python程序如何运行的.python的变量定义 一.python解释器: 用来翻译语 ...
- Bphero-UWB 基站0 和 电脑串口数据格式定义
基站0 通过串口将系统中测得的距离信息发送到电脑,电脑定位软件通过三边定位算法计算出TAG的坐标,基站0 和 定位软件之间的数据格式定义如下(对官方数据结构进行了简化) 更多UWB定位信息请参阅论坛b ...
- C++ otlv4 连接 sql server 数据库小记
otlv4介绍: http://otl.sourceforge.net/ 测试代码 // testotlv4.cpp : 定义控制台应用程序的入口点. // #include "stdafx ...
- LDAP & Implementation
LDAP & Implementation 一.什么是LDAP? (一)在介绍什么是LDAP之前,我们先来复习一个东西:“什么是目录服务?” 1. 目录服务是一个特殊的数据库,用来保存描述性的 ...
- hadoop常用操作命令
#############centos6.8IP常用操作命令#######################DEVICE=eth0TYPE=EthernetONBOOT=yesNM_CONTROLLED ...
- Vue(三十二)SSR服务端渲染Nuxt.js
初始化Nuxt.js项目步骤 1.使用脚手架工具 create-nuxt-app 创建Nuxt项目 使用yarn或者npm $ yarn create nuxt-app <项目名> 注:根 ...
- c# 集合的长度为什么是可变的
摘要: 写在前面:此随笔仅仅是作为个人学习总结,有不对的地方,请各位前辈指正O(∩_∩)O........ 一: 引入 在学习集合之前我们都学习过数组.可以知道数组的长度在声明的时候就已经被固定了,不 ...
- rest_framework之认证源码剖析
如果我们写API有人能访问,有人不能访问,则需要些认证. 如何知道该用户是否已登入? 如果用户登入成功,则给用户一个随机字符串,去访问另一个页面. 以前写session的时候,都是把session写c ...