java聊天服务器架构_基于Spring 4.0 的 Web Socket 聊天室/游戏服务端简单架构
在现在很多业务场景(比如聊天室),又或者是手机端的一些online游戏,都需要做到实时通信,那怎么来进行双向通信呢,总不见得用曾经很破旧的ajax每隔10秒或者每隔20秒来请求吧,我的天呐(
),这尼玛太坑了
跟webservice来相比,Web Socket可以做到保持长连接,或者说强连接,一直握手存在两端可以互相发送消息互相收到消息,而webservice是一次性的,你要我响应就必须要请求我一次(黄盖:“请鞭挞我吧!”)
注:浏览器需要使用高版本的chrome或者Firefox,Tomcat使用8
先来了解一下基本概念
一、WebSocket是HTML5出的,是一种协议,也就是说原版的HTTP协议没有变化的,又或者说这两者压根就是不一样的东西,HTTP本身就不支持强连接
二、Websocket是什么样的协议,具体有什么优点
首先,Websocket是一个持久化的协议,相对于HTTP这种非持久的协议来说。
举个栗子吧,简单来说
1) HTTP的生命周期通过Request来界定,也就是一个Request 对应一个Response,或者多个Request 对应多个Response,
也就是说request对应的response数量是恒定不变的。而且这个response也是被动的,不能主动发起,必须有request才会有response
那么Websocket究竟是啥玩意呢
首先Websocket是基于HTTP协议的,或者说引用了HTTP的协议来完成一小部分的握手
简单来说,客服的发起请求到服务端,服务端找到对应的小弟(服务助理),找到好,这个小弟就会一直和老大保持联系,为老大服务
三、Websocket的作用
曾经接触WebSocket之前,我接触过ajax轮询以及long poll ,先来说说这2个概念,因为至今还有一些小项目是这么做的
ajax轮询:
原理非常简单,JS控制让浏览器隔个几秒就发送一次请求,询问服务器是否有新信息,有的话就响应给客户端
以此循环获取后端的数据,同时浏览器又不需要刷新
简单的例子:OA首页显示流程,每个几秒刷新看看有没有需要处理的新流程出现
long poll:
long poll 其实原理跟 ajax轮询 差不多,都是采用循环的方式,不过采取的手段不太友好,是阻塞模型,客户端发起请求后,如果没响应,就一直不返回Response,直到有响应才返回,返回完之后,客户端再次建立连接,如此循环往复不亦乐乎。。。
从上面这两种方式看出他们都是在不断地建立HTTP连接,然后等待服务器处理,这样显得十分被动
那么缺点也随之而来:
这两种形式非常消耗资源,性能也不不好
好!接下来说说Websocket
Websocket的出现,使得资源不需要像之前那种方式那么浪费
它非常主动,服务端就可以主动推送信息给客户端
所以,只需建立一次HTTP请求,就可以做到源源不断的信息传送了。(就像你在手机上玩ol游戏,一开始建立连接后,你就一直保持在线,除非你断线再连)
下面贴出我的代码片段以及github地址
功能点:
spring websocket chating room
使用spring websocket实现聊天室基本功能
1.群发消息给所有人
2.悄悄话给某个人
效果:
主要代码:
pom.xml引入必要的库
1 <?xml version="1.0" encoding="UTF-8"?>
2
3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
4 4.0.0
5 com.lee
6 websocket
7 maven-spring-websocket-01
8 war
9 1.0.0-BUILD-SNAPSHOT
10
11
12
13 1.7
14 UTF-8
15 UTF-8
16
17 4.0.0.RELEASE
18
19 4.11
20
21
22 1.0.13
23 1.7.7
24
25
26
27
28
29 org.springframework
30 spring-core
31 ${spring.version}
32
33
34
35 org.springframework
36 spring-web
37 ${spring.version}
38
39
40
41 org.springframework
42 spring-webmvc
43 ${spring.version}
44
45
46
47
48 jstl
49 jstl
50 1.2
51
52
53
54
55 org.springframework
56 spring-test
57 ${spring.version}
58 test
59
60
61
62
63 org.springframework
64 spring-jdbc
65 ${spring.version}
66
67
68
69 junit
70 junit
71 4.8.2
72 test
73
74
75
76
77 org.springframework
78 spring-websocket
79 ${spring.version}
80
81
82 org.springframework
83 spring-messaging
84 ${spring.version}
85
86
87
88
89 com.fasterxml.jackson.core
90 jackson-databind
91 2.3.0
92
93
94
95 commons-fileupload
96 commons-fileupload
97 1.2.2
98
99
100 commons-io
101 commons-io
102 2.2
103
104
105
106
107 org.slf4j
108 slf4j-api
109 ${slf4j.version}
110 compile
111
112
113 ch.qos.logback
114 logback-classic
115 ${logback.version}
116 runtime
117
118
119
120
121 com.alibaba
122 druid
123 1.0.4
124
125
126
127
128 mysql
129 mysql-connector-java
130 5.1.29
131
132
133
134
135
136
137
138 org.apache.maven.plugins
139 maven-compiler-plugin
140
141 1.7
142 1.7
143
144
145
146
147
148
主要结构
HandshakeInterceptor.java
1 packagecom.lee.websocket;2
3 importjava.util.Map;4
5 importjavax.servlet.http.HttpSession;6
7 importorg.springframework.http.server.ServerHttpRequest;8 importorg.springframework.http.server.ServerHttpResponse;9 importorg.springframework.http.server.ServletServerHttpRequest;10 importorg.springframework.web.socket.WebSocketHandler;11
12 public class HandshakeInterceptor implementsorg.springframework.web.socket.server.HandshakeInterceptor {13
14 //进入hander之前的拦截
15 @Override16 public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Map map) throwsException {17 if (request instanceofServletServerHttpRequest) {18 ServletServerHttpRequest servletRequest =(ServletServerHttpRequest) request;19
20 String clientName = (String)servletRequest.getServletRequest().getParameter("name");21 System.out.println(clientName);22
23 HttpSession session = servletRequest.getServletRequest().getSession(true);24 //String userName = "lee";
25 if (session != null) {26 //使用userName区分WebSocketHandler,以便定向发送消息27 //String clientName = (String) session.getAttribute("WEBSOCKET_USERNAME");
28 map.put("WEBSOCKET_USERNAME", clientName);29 }30 }31 return true;32 }33
34 @Override35 public voidafterHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Exception e) {36
37 }38
39 }
HomeController.java
1 packagecom.lee.websocket;2
3 importjava.text.DateFormat;4 importjava.util.Date;5 importjava.util.Locale;6
7 importorg.slf4j.Logger;8 importorg.slf4j.LoggerFactory;9 importorg.springframework.stereotype.Controller;10 importorg.springframework.ui.Model;11 importorg.springframework.web.bind.annotation.RequestMapping;12 importorg.springframework.web.bind.annotation.RequestMethod;13
14 /**
15 * Handles requests for the application home page.16 */
17 @Controller18 public classHomeController {19
20 private static final Logger logger = LoggerFactory.getLogger(HomeController.class);21
22 /**
23 * Simply selects the home view to render by returning its name.24 */
25 @RequestMapping(value = "/", method =RequestMethod.GET)26 publicString home(Locale locale, Model model) {27 logger.info("Welcome home! The client locale is {}.", locale);28
29 Date date = newDate();30 DateFormat dateFormat =DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);31
32 String formattedDate =dateFormat.format(date);33
34 model.addAttribute("serverTime", formattedDate );35
36 return "home";37 }38
39 @RequestMapping(value = "/chat", method =RequestMethod.GET)40 publicString chat(Locale locale, Model model) {41 return "chat";42 }43
44 }
WebSocketConfig.java
1 packagecom.lee.websocket;2
3 importorg.springframework.context.annotation.Configuration;4 importorg.springframework.web.socket.config.annotation.EnableWebSocket;5 importorg.springframework.web.socket.config.annotation.WebSocketConfigurer;6 importorg.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;7
8 @Configuration9 @EnableWebSocket//开启websocket
10 public class WebSocketConfig implementsWebSocketConfigurer {11 @Override12 public voidregisterWebSocketHandlers(WebSocketHandlerRegistry registry) {13 registry.addHandler(new WebSocketHander(),"/echo").addInterceptors(new HandshakeInterceptor()); //支持websocket 的访问链接
14 registry.addHandler(new WebSocketHander(),"/sockjs/echo").addInterceptors(new HandshakeInterceptor()).withSockJS(); //不支持websocket的访问链接
15 }16 }
WebSocketHander.java
1 packagecom.lee.websocket;2
3 importjava.io.IOException;4 importjava.util.ArrayList;5
6 importorg.slf4j.Logger;7 importorg.slf4j.LoggerFactory;8 importorg.springframework.web.socket.CloseStatus;9 importorg.springframework.web.socket.TextMessage;10 importorg.springframework.web.socket.WebSocketHandler;11 importorg.springframework.web.socket.WebSocketMessage;12 importorg.springframework.web.socket.WebSocketSession;13
14 public class WebSocketHander implementsWebSocketHandler {15 private static final Logger logger = LoggerFactory.getLogger(WebSocketHander.class);16
17 private static final ArrayList users = new ArrayList<>();18
19 //初次链接成功执行
20 @Override21 public void afterConnectionEstablished(WebSocketSession session) throwsException {22 logger.debug("链接成功......");23 users.add(session);24 String userName = (String) session.getHandshakeAttributes().get("WEBSOCKET_USERNAME");25 if(userName!= null){26 session.sendMessage(new TextMessage("欢迎来到Nathan的聊天室,我们开始聊天吧!~"));27 }28 }29
30 //接受消息处理消息
31 @Override32 public void handleMessage(WebSocketSession session, WebSocketMessage> webSocketMessage) throwsException {33 String clientName = (String) session.getHandshakeAttributes().get("WEBSOCKET_USERNAME");34
35 clientName = "" + clientName + "";36
37 String msg =webSocketMessage.getPayload().toString();38 String charter = "";39
40 String msgs[] = msg.split("\\|");41 if (msgs.length > 1) {42 msg = msgs[1];43 charter = msgs[0];44 sendMessageToUser(charter, new TextMessage(clientName + " 悄悄地对你说 :" +msg));45 } else{46 sendMessageToUsers(new TextMessage(clientName + " 说:" +msg));47 }48
49 }50
51 @Override52 public void handleTransportError(WebSocketSession webSocketSession, Throwable throwable) throwsException {53 if(webSocketSession.isOpen()){54 webSocketSession.close();55 }56 logger.debug("链接出错,关闭链接......");57 users.remove(webSocketSession);58 }59
60 @Override61 public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) throwsException {62 logger.debug("链接关闭......" +closeStatus.toString());63 users.remove(webSocketSession);64 }65
66 @Override67 public booleansupportsPartialMessages() {68 return false;69 }70
71 /**
72 * 给所有在线用户发送消息73 *74 *@parammessage75 */
76 public voidsendMessageToUsers(TextMessage message) {77 for(WebSocketSession user : users) {78 try{79 if(user.isOpen()) {80 user.sendMessage(message);81 }82 } catch(IOException e) {83 e.printStackTrace();84 }85 }86 }87
88 /**
89 * 给某个用户发送消息90 *91 *@paramuserName92 *@parammessage93 */
94 public voidsendMessageToUser(String userName, TextMessage message) {95 for(WebSocketSession user : users) {96 if (user.getHandshakeAttributes().get("WEBSOCKET_USERNAME").equals(userName)) {97 try{98 if(user.isOpen()) {99 user.sendMessage(message);100 }101 } catch(IOException e) {102 e.printStackTrace();103 }104 break;105 }106 }107 }108 }
Person.java
1 packagecom.lee.websocket.entity;2
3 public classPerson {4
5 private intage;6 privateString name;7 privateString sex;8
9 public intgetAge() {10 returnage;11 }12 public void setAge(intage) {13 this.age =age;14 }15 publicString getName() {16 returnname;17 }18 public voidsetName(String name) {19 this.name =name;20 }21 publicString getSex() {22 returnsex;23 }24 public voidsetSex(String sex) {25 this.sex =sex;26 }27
28 }
chat.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
webSocket测试
16
17 varchater;18
19 $(function(){20
21 varwebsocket;22 functionconnectServer() {23 var clientName = $("#client_name").val();24 if ("WebSocket" inwindow) {25 websocket = new WebSocket("ws://127.0.0.1:8080/websocket/echo?name=" +clientName);26 } else if ("MozWebSocket" inwindow) {27 alert("MozWebSocket");28 websocket = new MozWebSocket("ws://echo");29 } else{30 alert("SockJS");31 websocket = new SockJS("http://127.0.0.1:8080/websocket/sockjs/echo");32 }33 }34
35 //websocket.onopen = function (evnt) {
36 //$("#tou").html("链接服务器成功!")
37 //};
38 //websocket.onmessage = function (evnt) {
39 //$("#msg").html($("#msg").html() + "
" + evnt.data);
40 //};
41 //websocket.onerror = function (evnt) {
42 //};
43 //websocket.onclose = function (evnt) {
44 //$("#tou").html("与服务器断开了链接!")
45 //}
46
47 $("#conncet_server").bind("click", function() {48 connectServer();49
50 websocket.onopen = function(evnt) {51 $("#tou").html("链接服务器成功!")52 };53 websocket.onmessage = function(evnt) {54 $("#msg").html($("#msg").html() + "
" +evnt.data);55 };56 websocket.onerror = function(evnt) {57 };58 websocket.onclose = function(evnt) {59 $("#tou").html("与服务器断开了链接!")60 }61 });62
63 $("#send").bind("click", function() {64 send();65 });66
67 functionsend(){68 if (websocket != null) {69 var message = document.getElementById("message").value;70
71 if ($.trim(chater) != "") {72 message = chater + "|" +message;73 }74
75 websocket.send(message);76 } else{77 alert("未与服务器链接.");78 }79 }80 });81
82 functionchangeChater(e) {83 chater =$(e).html();84 alert("您将和" + chater + "进行聊天...");85 }86
87
88
89
90
91
92
93
94
95
96
97 连接服务器
98
99
100
101
102
103
104
105
106
107
108 发送
109
110
111
112
113
114
java聊天服务器架构_基于Spring 4.0 的 Web Socket 聊天室/游戏服务端简单架构相关推荐
- 基于Spring 4.0 的 Web Socket 聊天室/游戏服务端简单架构
跟webservice来相比,Web Socket可以做到保持长连接,或者说强连接,一直握手存在两端可以互相发送消息互相收到消息,而webservice是一次性的,你要我响应就必须要请求我一次(黄盖: ...
- 浅谈游戏服务端开发-架构
网络游戏程序分为客户端和服务端.客户端负责图形渲染.交互和一些简单校验处理,服务端负责业务逻辑处理.数据存储. 我们开发一个游戏demo,服务端程序可以是一个单线程的服务进程.它包含网络通信.业务逻辑 ...
- java aop管理权限_基于spring aop 权限管理系统原型 - andyj2ee - BlogJava
此权限管理系统把待访问的业务层方法做为权限管理中的资源,通过spring aop 对接口方法进行拦截,来实现权限的管理,可以实现细粒度的权限控制. 在上文体验了spring aop 一些特性,aop ...
- java http 服务器搭建_基于http.server搭建局域网服务器过程解析
不知道大家有没有遇到过这样的情况, 在做项目或者研发的时候,迫切想要将一个文件传输给另一台电脑,却找不到u盘,于是麻烦的通过登陆qq.微信等社交软件 ,或者邮箱等工具进行传输,十分麻烦,让人苦恼.都说 ...
- paho架构_基于paho springboot集成mqtt实现消息的发布订阅 - 人人都是架构师
1.首先添加pom依赖 org.springframework.boot spring-boot-starter-integration org.springframework.integration ...
- java开源springboot项目_使用Spring Boot的10多个免费开源项目
这是一个真实的应用程序,为 Spring.io 网站提供支持.它正在生产中,每天都有成千上万的用户使用. 我强烈建议这个项目,你将学习有关Spring框架生态系统,Elasticsearch,Gr ...
- java项目----教务管理系统_基于Java的教务管理系统
java项目----教务管理系统_基于Java的教务管理系统 2022-04-22 18:18·java基础 最近为客户开发了一套学校用教务管理系统,主要实现学生.课程.老师.选课等相关的信息化管理功 ...
- java项目-第99期基于spring+springmvc+hibernate的在线问卷答题系统-计算机毕业设计
java项目-第99期基于spring+springmvc+hibernate的在线问卷答题系统[毕业设计] [源码请到下载专栏下载] 1.项目简述 今天分享的项目是<在线问卷答题系统>, ...
- Mongodb网页管理工具,基于Spring Boot2.0,前端采用layerUI实现
源码:https://github.com/a870439570/Mongodb-WeAdmin 项目介绍 Mongodb网页管理工具,基于Spring Boot2.0,前端采用layerUI实现. ...
- 基于滴滴云的棋牌游戏服务端架构设计
现在小团队开发的棋牌游戏有很多,棋牌行业的相互攻击是非常普遍的现象,同行之间往往会采取 DDOS.CC 等攻击的手段来打击对手,这是目前棋牌运营商们面临的比较严峻的一个问题,那么在设计棋牌游戏服务端架 ...
最新文章
- 关于web.xml3.0启动报错
- ue4 怎么传递变量到另一个蓝图_资深建模教你放置UE4蓝图节点,所以你就不要偷懒啦,认真点学...
- .Net程序员安卓学习之路5:使用xutils注入View和事件以及图片的显示
- famous javascript library.
- HTTP之Cookie和Session(C++ Qt框架实现)
- NOIP 2015 提高组 Day2
- Oracle技术之索引与Null值对于Hints及执行计划的影响
- SQL 游标使用实例
- Linux进程间通信——消息队列
- 一个果农儿子的心声,你倾听一下吧?
- android 图片合成pdf文件,怎样将图片转换成pdf文件时将它们合并成一个pdf文件?...
- linux下载git并为git配置连接ssh
- android 9.0极光推送闪退,极光推送集成Module中遇到的坑
- linux命令报错,在Linux执行命令报错”Arg list too long”的原因分析 – 运维派
- 尝试编写一个加密程序,加密方法将明文的字母变成其后的第4个字母,**字母表首尾相连。非字母符号** 不加密。 例如输入“China“, 输出密文“Glmre“, 输入 “ab123“, 输出 “ef1
- 初学JavaScript:BOM(浏览器对象模型)介绍
- 遥感深度学习数据集汇总(更新中)
- 猿创征文|一文吃透JAVA初学者的开发工具
- 海外用户用不了鸿蒙系统,鸿蒙系统国内遇冷海外好评 技术壁垒依然存在
- 计算机科学与技术毕业设计源码,计算机科学与技术专业(毕业论文)基于网络的同学录设计与实现源代码.doc...