博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
WebSocket实现即时聊天室
阅读量:5894 次
发布时间:2019-06-19

本文共 6209 字,大约阅读时间需要 20 分钟。

  hot3.png

原理

很多网站为了实现即时聊天,使用的是轮询方式(在特定的时间间隔,由浏览器向服务器端发出 Http request,然后由服务器返回最新的数据)实现。这种传统的 Http request的方式有个明显的缺点,浏览器需要不断的向服务器发出请求,然而HTTP request 的header是非常长的,里面包含的有用数据可能只是一个很小的值,这样会占用很多的带宽。 比较新的方式是Comet---用了Ajax,但是还是要发出请求。 但是在WebSocket API中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。这样做的两大好处是

  1. Header 互相沟通的Header是很小的-大概只有 2 Bytes
  2. Server Push 服务器的推送,服务器不再被动的接收到浏览器的request之后才返回数据,而是在有新数据时就主动推送给浏览器。

开发基于WebSocket协议的聊天室

开发环境

MyEclipse2014、JDK1.7.45 64位、Tomcat8

WebSocketConfig

package com.sx2.websocket;import java.util.Set;import javax.websocket.Endpoint;import javax.websocket.server.ServerApplicationConfig;import javax.websocket.server.ServerEndpointConfig;/** *  * @author Jin *	在Tomcat启动的时候会加载此类(因为实现了ServerApplicationConfig接口) */public class WebSocketConfig implements ServerApplicationConfig{	@Override	public Set
> getAnnotatedEndpointClasses(Set
> scan) { /* * 这里会自动扫描带有@ServerEndpoint注解的类 * 返回它们的类名集合,这里可以做一些过滤,比如过滤测试用的带有@ServerEndpoint注解的类 * 最后一定要返回过滤后的set集合,相当于注册服务 * 最后一定要返回过滤后的set集合,相当于注册服务 * 最后一定要返回过滤后的set集合,相当于注册服务 */ return scan; } @Override public Set
getEndpointConfigs( Set
> arg0) { return null; }}

chatSocket.java

import java.io.IOException;import java.io.UnsupportedEncodingException;import java.net.URLDecoder;import java.util.Date;import java.util.HashMap;import java.util.HashSet;import java.util.Iterator;import java.util.Map;import java.util.Set;import javax.websocket.OnClose;import javax.websocket.OnMessage;import javax.websocket.OnOpen;import javax.websocket.Session;import javax.websocket.server.ServerEndpoint;import com.alibaba.fastjson.JSONObject;import com.sx2.pojo.WebSocketResult;/** *  * @author Jin * 这里带有@ServerEndpoint注解,会自动被扫描到 */@ServerEndpoint("/chatSocket")public class ChatSocket {	//所有的实例的集合	private  static  Set
sockets=new HashSet
(); //保存每个username对应的用户头像,这里只是这个项目中需要,如果实际项目中不需要,此变量无用 private static Map
photos = new HashMap
(); //保存每个用户的用户名 private static Set
names=new HashSet
(); //每个用户进入聊天室,都会开启一个session,要注意的是这里的session是javax.websocket.Session private Session session; //当有用户进入聊天室时,保存用户名 private String username; //当有用户进入聊天室时,保存用户头像,不是必须的 private String photo; /** * 每当有用户进入聊天室时,都会执行一次此函数 * @param session */ @OnOpen public void open(Session session){ this.session=session; sockets.add(this); //这里的逻辑是得到请求路径后的参数 //比如:ws://localhost:8080/SX2/chatSocket?username=jin&photo=/image/user/b3.png",那么queryString就是username=jin&photo=/image/user/b3.png //username为用户的用户名,是必须的。photo为用户的头像,看实际需要并不是必须的 String queryString = session.getQueryString(); //对得到queryString进行切割,得到用户名和头像 String[] infos = queryString.split("&"); this.username = infos[0].substring(infos[0].indexOf("=") + 1); this.photo = infos[1].substring(infos[1].indexOf("=") + 1); //WebSocket返回值的包装类 WebSocketResult message = new WebSocketResult(); String encodeUsername = ""; try { if(this.username.matches("[A-Za-z]")){ //如果用户的用户名是纯英文,比如Tom,Jerry,不用编码 encodeUsername = this.username; }else{ //如果用户的用户名不是纯英文的,则需要编码 encodeUsername = URLDecoder.decode(this.username,"UTF-8"); } this.username = encodeUsername; //将经过处理的用户名,添加到用户名集合中 names.add( encodeUsername); //将用户名集合放到返回值中 message.setNames(names); photos.put(encodeUsername, photo); message.setPhotos(photos); //将欢迎信息放到返回值中 message.setWelCome(encodeUsername+"进入聊天室!!"); //将返回值的包装类转为json字符串,向所有人打印欢迎信息。 broadcast(sockets, JSONObject.toJSONString(message)); } catch (UnsupportedEncodingException e1) { // TODO Auto-generated catch block message.setWelCome("服务器异常!"); broadcast(sockets, JSONObject.toJSONString(message)); } } @SuppressWarnings("deprecation") /** * 当有用户发送消息时,会执行此函数 * @param session 为此用户开启的session * @param msg 用户发送的消息文本 */ @OnMessage public void receive(Session session,String msg ){ WebSocketResult message=new WebSocketResult(); //将消息文本放到返回值中 message.setSendMsg(msg); //将来自哪个用户放到返回值中 message.setFrom(this.username); //将发送日期放到返回值中 message.setDate(new Date().toLocaleString()); //用户头像 message.setPhotos(photos); //向所有人打印发送的消息 broadcast(sockets, JSONObject.toJSONString(message)); } /** * * @param session 为此用户开启的session */ @OnClose public void close(Session session){ //从实例集合中移除此实例 sockets.remove(this); //从用户名集合中移除此用户名 names.remove(this.username); //从头像集合中移除此用户的头像 photos.remove(this.username); WebSocketResult message=new WebSocketResult(); //将欢送消息放到返回值中 message.setWelCome(this.username+"退出聊天室!!"); //重新设置用户名集合 message.setNames(names); //重新设置头像集合 message.setPhotos(photos); //向所有人打印欢送消息 broadcast(sockets, JSONObject.toJSONString(message)); } /** * * @param ss 所有实例集合 * @param msg 要向浏览器端发送的json字符串 */ public void broadcast(Set
ss ,String msg ){ for (Iterator
iterator = ss.iterator(); iterator.hasNext();) { ChatSocket chatSocket = (ChatSocket) iterator.next(); try { //使用session的getBasicRemote方法向浏览器端发送json字符串 chatSocket.session.getBasicRemote().sendText(msg); } catch (IOException e) { e.printStackTrace(); } } }}

WebSocketResult.java

import java.util.Map;import java.util.Set;/** *  * @author Jin * WebSocket返回值的包装类 */public class WebSocketResult {		private String sendMsg;		private String date;		private String from;		private String welCome;		private Set
names; private Map
photos; public String getWelCome() { return welCome; } public void setWelCome(String welCome) { this.welCome = welCome; } public String getSendMsg() { return sendMsg; } public void setSendMsg(String sendMsg) { this.sendMsg = sendMsg; } public String getDate() { return date; } public void setDate(String date) { this.date = date; } public String getFrom() { return from; } public void setFrom(String from) { this.from = from; } public Set
getNames() { return names; } public void setNames(Set
names) { this.names = names; } public Map
getPhotos() { return photos; } public void setPhotos(Map
photos) { this.photos = photos; }}

客户端代码

Apache Tomcat WebSocket Examples: Chat

转载于:https://my.oschina.net/zili/blog/1031431

你可能感兴趣的文章
jQuery自动完成点击html元素
查看>>
[算法]基于分区最近点算法的二维平面
查看>>
linux在文件打包和压缩
查看>>
webpack多页应用架构系列(七):开发环境、生产环境傻傻分不清楚?
查看>>
构建 iOS 界面:子类化 Views
查看>>
笨办法学C 练习1:启用编译器
查看>>
树的总结--树的性质(树的深度) leetcode
查看>>
在 IIS 下添加 FLV 类型文件的支持
查看>>
穿过任意防火墙NAT的远程控制软件TeamViewer
查看>>
nagios短信报警(飞信fetion20080522004-linrh4)
查看>>
【Android游戏开发之六】在SurfaceView中添加组件!!!!并且相互交互数据!!!!...
查看>>
异常处理汇总-开发工具
查看>>
[LeetCode] Excel Sheet Column Number 求Excel表列序号
查看>>
通过浏览器直接打开Android应用程序
查看>>
MVC调用SVC无法找到资源解决问题
查看>>
div加jquery实现iframe标签的功能
查看>>
解决Yapi 插件运行不支持文件上传的问题解决
查看>>
Windows路由表详解
查看>>
MySQL从库记录binlog日志出错一例
查看>>
2015年度扯淡
查看>>