在现在很多业务场景(比如聊天室),又或者是手机端的一些online游戏,都需要做到实时通信,那怎么来进行双向通信呢,总不见得用曾经很破旧的ajax每隔10秒或者每隔20秒来请求吧,我的天呐,这尼玛太坑了
跟webservice来相比,Web Socket可以做到保持长连接,或者说强连接,一直握手存在两端可以互相发送消息互相收到消息,而webservice是一次性的,你要我响应就必须要请求我一次
注:浏览器需要使用高版本的chrome或者Firefox,Tomcat使用8
先借用一下知乎某大神的原文:
作者:Ovear
链接:http://www.zhihu.com/question/20215561/answer/40316953
来源:知乎
一、WebSocket是HTML5出的东西(协议),也就是说HTTP协议没有变化,或者说没关系,但HTTP是不支持持久连接的(长连接,循环连接的不算)首先HTTP有1.1和1.0之说,也就是所谓的keep-alive,把多个HTTP请求合并为一个,但是Websocket其实是一个新协议,跟HTTP协议基本没有关系,只是为了兼容现有浏览器的握手规范而已,也就是说它是HTTP协议上的一种补充可以通过这样一张图理解
有交集,但是并不是全部。
另外Html5是指的一系列新的API,或者说新规范,新技术。Http协议本身只有1.0和1.1,而且跟Html本身没有直接关系。。
通俗来说,你可以用HTTP
协议传输非Html
数据,就是这样=。=
再简单来说,
层级不一样。
二、Websocket是什么样的协议,具体有什么优点首先,Websocket是一个
持久化的协议,相对于HTTP这种
非持久的协议来说。
简单的举个例子吧,用目前应用比较广泛的PHP生命周期来解释。
1) HTTP的生命周期通过Request来界定,也就是一个Request 一个Response,那么
在HTTP1.0
中,这次HTTP请求就结束了。
在HTTP1.1中进行了改进,使得有一个keep-alive,也就是说,在一个HTTP连接中,可以发送多个Request,接收多个Response。
但是请记住 Request = Response , 在HTTP中永远是这样,也就是说一个request只能有一个
response。而且这个response也是
被动的,不能主动发起。
教练,你BB了这么多,跟Websocket有什么关系呢?_(:з」∠)_好吧,我正准备说Websocket呢。。
首先Websocket是基于HTTP协议的,或者说
借用了HTTP的协议来完成一部分握手。
在握手阶段是一样的
-------以下涉及专业技术内容,不想看的可以跳过lol:,或者只看加黑内容--------
首先我们来看个典型的Websocket握手(借用Wikipedia的。。)
GET /chat HTTP/1.1Host: server.example.comUpgrade: websocketConnection: UpgradeSec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==Sec-WebSocket-Protocol: chat, superchatSec-WebSocket-Version: 13Origin: http://example.com
熟悉HTTP的童鞋可能发现了,这段类似HTTP协议的握手请求中,多了几个东西。
我会顺便讲解下作用。
Upgrade: websocketConnection: Upgrade
这个就是Websocket的核心了,告诉
Apache、Nginx等服务器:
注意啦,窝发起的是Websocket协议,快点帮我找到对应的助理处理~不是那个老土的HTTP。Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==Sec-WebSocket-Protocol: chat, superchatSec-WebSocket-Version: 13
首先,Sec-WebSocket-Key 是一个Base64 encode的值,这个是浏览器
随机生成的,告诉服务器:
泥煤,不要忽悠窝,我要验证尼是不是真的是Websocket助理。然后,Sec_WebSocket-Protocol 是一个用户定义的字符串,用来区分同
URL下,不同的服务所需要的协议。简单理解:
今晚我要服务A,别搞错啦~最后,Sec-WebSocket-Version 是告诉服务器所使用的Websocket Draft(协议版本),在最初的时候,Websocket协议还在 Draft 阶段,各种奇奇怪怪的协议都有,而且还有很多期奇奇怪怪不同的东西,什么Firefox和Chrome用的不是一个版本之类的,当初Websocket协议太多可是一个大难题。。不过现在还好,已经定下来啦~大家都使用的一个东西~ 脱水:
服务员,我要的是13岁的噢→_→然后服务器会返回下列东西,表示已经接受到请求, 成功建立Websocket啦!
HTTP/1.1 101 Switching ProtocolsUpgrade: websocketConnection: UpgradeSec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=Sec-WebSocket-Protocol: chat
这里开始就是HTTP最后负责的区域了,告诉客户,我已经成功切换协议啦~
Upgrade: websocketConnection: Upgrade
依然是固定的,告诉客户端即将升级的是Websocket协议,而不是mozillasocket,lurnarsocket或者shitsocket。
然后,Sec-WebSocket-Accept 这个则是经过服务器确认,并且加密过后的 Sec-WebSocket-Key。服务器:
好啦好啦,知道啦,给你看我的ID CARD来证明行了吧。。后面的,Sec-WebSocket-Protocol 则是表示最终使用的协议。
至此,HTTP已经完成它所有工作了,接下来就是完全按照Websocket协议进行了。
具体的协议就不在这阐述了。
------------------技术解析部分完毕------------------
你TMD又BBB了这么久,那到底Websocket有什么鬼用,http long poll,或者ajax轮询不都可以实现实时信息传递么。
好好好,年轻人,那我们来讲一讲Websocket有什么用。
来给你吃点胡(苏)萝(丹)卜(红)
三、Websocket的作用在讲Websocket之前,我就顺带着讲下 long poll 和 ajax轮询 的原理。
首先是 ajax轮询 ,ajax轮询 的原理非常简单,让浏览器隔个几秒就发送一次请求,询问服务器是否有新信息。
场景再现:
客户端:啦啦啦,有没有新信息(Request)
服务端:没有(Response)
客户端:啦啦啦,有没有新信息(Request)
服务端:没有。。(Response)
客户端:啦啦啦,有没有新信息(Request)
服务端:你好烦啊,没有啊。。(Response)
客户端:啦啦啦,有没有新消息(Request)
服务端:好啦好啦,有啦给你。(Response)
客户端:啦啦啦,有没有新消息(Request)
服务端:。。。。。没。。。。没。。。没有(Response) ---- loop
long poll
long poll 其实原理跟 ajax轮询 差不多,都是采用轮询的方式,不过采取的是阻塞模型(一直打电话,没收到就不挂电话),也就是说,客户端发起连接后,如果没消息,就一直不返回Response给客户端。直到有消息才返回,返回完之后,客户端再次建立连接,周而复始。
场景再现
客户端:啦啦啦,有没有新信息,没有的话就等有了才返回给我吧(Request)
服务端:额。。 等待到有消息的时候。。来 给你(Response)
客户端:啦啦啦,有没有新信息,没有的话就等有了才返回给我吧(Request) -loop
从上面可以看出其实这两种方式,都是在不断地建立HTTP连接,然后等待服务端处理,可以体现HTTP协议的另外一个特点,
被动性。
何为被动性呢,其实就是,服务端不能主动联系客户端,只能有客户端发起。
简单地说就是,服务器是一个很懒的冰箱(这是个梗)(不会、不能主动发起连接),但是上司有命令,如果有客户来,不管多么累都要好好接待。
说完这个,我们再来说一说上面的缺陷(原谅我废话这么多吧OAQ)
从上面很容易看出来,不管怎么样,上面这两种都是非常消耗资源的。
ajax轮询 需要服务器有很快的处理速度和资源。(速度)
long poll 需要有很高的并发,也就是说同时接待客户的能力。(场地大小)
所以ajax轮询 和long poll 都有可能发生这种情况。
客户端:啦啦啦啦,有新信息么?服务端:月线正忙,请稍后再试(503 Server Unavailable)客户端:。。。。好吧,啦啦啦,有新信息么?服务端:月线正忙,请稍后再试(503 Server Unavailable)
客户端:然后服务端在一旁忙的要死:冰箱,我要更多的冰箱!更多。。更多。。(我错了。。这又是梗。。)--------------------------
言归正传,我们来说Websocket吧通过上面这个例子,我们可以看出,这两种方式都不是最好的方式,需要很多资源。
一种需要更快的速度,一种需要更多的'电话'。这两种都会导致'电话'的需求越来越高。
哦对了,忘记说了HTTP还是一个无状态协议。(感谢评论区的各位指出OAQ)
通俗的说就是,服务器因为每天要接待太多客户了,是个
健忘鬼,你一挂电话,他就把你的东西全忘光了,把你的东西全丢掉了。你第二次还得再告诉服务器一遍。
所以在这种情况下出现了,Websocket出现了。
他解决了HTTP的这几个难题。
首先,
被动性,当服务器完成协议升级后(HTTP->Websocket),服务端就可以主动推送信息给客户端啦。
所以上面的情景可以做如下修改。
客户端:啦啦啦,我要建立Websocket协议,需要的服务:chat,Websocket协议版本:17(HTTP Request)
服务端:ok,确认,已升级为Websocket协议(HTTP Protocols Switched)
客户端:麻烦你有信息的时候推送给我噢。。
服务端:ok,有的时候会告诉你的。
服务端:balabalabalabala
服务端:balabalabalabala
服务端:哈哈哈哈哈啊哈哈哈哈
服务端:笑死我了哈哈哈哈哈哈哈
就变成了这样,只需要经过
一次HTTP请求,就可以做到源源不断的信息传送了。(在程序设计中,这种设计叫做回调,即:你有信息了再来通知我,而不是我傻乎乎的每次跑来问你)
这样的协议解决了上面同步有延迟,而且还非常消耗资源的这种情况。
那么为什么他会解决服务器上消耗资源的问题呢?
其实我们所用的程序是要经过两层代理的,即
HTTP协议在Nginx等服务器的解析下,然后再传送给相应的
Handler(PHP等)来处理。
简单地说,我们有一个非常快速的接
线员(Nginx),他负责把问题转交给相应的
客服(Handler)。
本身
接线员基本上速度是足够的,但是每次都卡在
客服(Handler)了,老有
客服处理速度太慢。,导致客服不够。
Websocket就解决了这样一个难题,建立后,可以直接跟接线员建立持
久连接,有信息的时候客服想办法通知接线员,然后
接线员在统一转交给客户。
这样就可以解决客服处理速度过慢的问题了。
同时,在传统的方式上,要不断的建立,关闭HTTP协议,由于HTTP是非状态性的,每次都要
重新传输identity info(鉴别信息),来告诉服务端你是谁。
虽然接线员很快速,但是每次都要听这么一堆,效率也会有所下降的,同时还得不断把这些信息转交给客服,不但浪费客服的
处理时间,而且还会在网路传输中消耗
过多的流量/时间。但是Websocket只需要
一次HTTP握手,所以说整个通讯过程是建立在一次连接/状态中,也就避免了HTTP的非状态性,服务端会一直知道你的信息,直到你关闭请求,这样就解决了接线员要反复解析HTTP协议,还要查看identity info的信息。
同时由
客户主动询问,转换为
服务器(推送)有信息的时候就发送(当然客户端还是等主动发送信息过来的。。),没有信息的时候就交给接线员(Nginx),不需要占用本身速度就慢的
客服(Handler)了
--------------------
至于怎么在不支持Websocket的客户端上使用Websocket。。答案是:
不能但是可以通过上面说的 long poll 和 ajax 轮询来
模拟出类似的效果下面贴出我的代码片段以及github地址
功能点:
spring websocket chating room
使用spring websocket实现聊天室基本功能
1.群发消息给所有人
2.悄悄话给某个人
效果:
主要代码:
pom.
1 <??> 2 <project ="http://maven.apache.org/POM/4.0.0" ="http://www.w3.org/2001/ 3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 4 <modelVersion>4.0.0</modelVersion> 5 <groupId>com.lee</groupId> 6 <artifactId>websocket</artifactId> 7 <name>maven-spring-websocket-01</name> 8 <packaging>war</packaging> 9 <version>1.0.0-BUILD-SNAPSHOT</version> 10 11 <properties> 12 13 <java.version>1.7</java.version> 14 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 15 <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> 16 17 <spring.version>4.0.0.RELEASE</spring.version> 18 19 <junit.version>4.11</junit.version> 20 21 <!-- Logging --> 22 <logback.version>1.0.13</logback.version> 23 <slf4j.version>1.7.7</slf4j.version> 24 </properties> 25 26 <dependencies> 27 <!--spring MVC --> 28 <dependency> 29 <groupId>org.springframework</groupId> 30 <artifactId>spring-core</artifactId> 31 <version>${spring.version}</version> 32 </dependency> 33 34 <dependency> 35 <groupId>org.springframework</groupId> 36 <artifactId>spring-web</artifactId> 37 <version>${spring.version}</version> 38 </dependency> 39 40 <dependency> 41 <groupId>org.springframework</groupId> 42 <artifactId>spring-webmvc</artifactId> 43 <version>${spring.version}</version> 44 </dependency> 45 46 <!-- jstl --> 47 <dependency> 48 <groupId>jstl</groupId> 49 <artifactId>jstl</artifactId> 50 <version>1.2</version> 51 </dependency> 52 53 <!--spring测试框架 --> 54 <dependency> 55 <groupId>org.springframework</groupId> 56 <artifactId>spring-test</artifactId> 57 <version>${spring.version}</version> 58 <scope>test</scope> 59 </dependency> 60 61 <!--spring数据库操作库 --> 62 <dependency> 63 <groupId>org.springframework</groupId> 64 <artifactId>spring-jdbc</artifactId> 65 <version>${spring.version}</version> 66 </dependency> 67 68 <dependency> 69 <groupId>junit</groupId> 70 <artifactId>junit</artifactId> 71 <version>4.8.2</version> 72 <scope>test</scope> 73 </dependency> 74 75 <!--spring websocket库 --> 76 <dependency> 77 <groupId>org.springframework</groupId> 78 <artifactId>spring-websocket</artifactId> 79 <version>${spring.version}</version> 80 </dependency> 81 <dependency> 82 <groupId>org.springframework</groupId> 83 <artifactId>spring-messaging</artifactId> 84 <version>${spring.version}</version> 85 </dependency> 86 87 <!--jackson用于json操作 --> 88 <dependency> 89 <groupId>com.faster</groupId> 90 <artifactId>jackson-databind</artifactId> 91 <version>2.3.0</version> 92 </dependency> 93 94 <dependency> 95 <groupId>commons-fileupload</groupId> 96 <artifactId>commons-fileupload</artifactId> 97 <version>1.2.2</version> 98 </dependency> 99 <dependency>100 <groupId>commons-io</groupId>101 <artifactId>commons-io</artifactId>102 <version>2.2</version>103 </dependency>104 105 <!-- Logging with SLF4J & LogBack -->106 <dependency>107 <groupId>org.slf4j</groupId>108 <artifactId>slf4j-api</artifactId>109 <version>${slf4j.version}</version>110 <scope>compile</scope>111 </dependency>112 <dependency>113 <groupId>ch.qos.logback</groupId>114 <artifactId>logback-classic</artifactId>115 <version>${logback.version}</version>116 <scope>runtime</scope>117 </dependency>118 119 <!--使用阿里的连接池 -->120 <dependency>121 <groupId>com.alibaba</groupId>122 <artifactId>druid</artifactId>123 <version>1.0.4</version>124 </dependency>125 126 <!--mysql connector -->127 <dependency>128 <groupId>mysql</groupId>129 <artifactId>mysql-connector-java</artifactId>130 <version>5.1.29</version>131 </dependency>132 133 </dependencies>134 135 <build>136 <plugins>137 <plugin>138 <groupId>org.apache.maven.plugins</groupId>139 <artifactId>maven-compiler-plugin</artifactId>140 <configuration>141 <source>1.7</source>142 <target>1.7</target>143 </configuration>144 </plugin>145 </plugins>146 </build>147 148 </project>
主要结构
HandshakeInterceptor.java
1 package com.lee.websocket; 2 3 import java.util.Map; 4 5 import javax.servlet.http.HttpSession; 6 7 import org.springframework.http.server.ServerHttpRequest; 8 import org.springframework.http.server.ServerHttpResponse; 9 import org.springframework.http.server.ServletServerHttpRequest;10 import org.springframework.web.socket.WebSocketHandler;11 12 public class HandshakeInterceptor implements org.springframework.web.socket.server.HandshakeInterceptor {13 14 //进入hander之前的拦截15 @Override16 public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Map<String, Object> map) throws Exception {17 if (request instanceof ServletServerHttpRequest) {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 void afterHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Exception e) {36 37 }38 39 }
HomeController.java
1 package com.lee.websocket; 2 3 import java.text.DateFormat; 4 import java.util.Date; 5 import java.util.Locale; 6 7 import org.slf4j.Logger; 8 import org.slf4j.LoggerFactory; 9 import org.springframework.stereotype.Controller;10 import org.springframework.ui.Model;11 import org.springframework.web.bind.annotation.RequestMapping;12 import org.springframework.web.bind.annotation.RequestMethod;13 14 /**15 * Handles requests for the application home page.16 */17 @Controller18 public class HomeController {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 public String home(Locale locale, Model model) {27 logger.info("Welcome home! The client locale is {}.", locale);28 29 Date date = new Date();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 public String chat(Locale locale, Model model) {41 return "chat";42 }43 44 }
WebSocketConfig.java
1 package com.lee.websocket; 2 3 import org.springframework.context.annotation.Configuration; 4 import org.springframework.web.socket.config.annotation.EnableWebSocket; 5 import org.springframework.web.socket.config.annotation.WebSocketConfigurer; 6 import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; 7 8 @Configuration 9 @EnableWebSocket//开启websocket10 public class WebSocketConfig implements WebSocketConfigurer {11 @Override12 public void registerWebSocketHandlers(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 package com.lee.websocket; 2 3 import java.io.IOException; 4 import java.util.ArrayList; 5 6 import org.slf4j.Logger; 7 import org.slf4j.LoggerFactory; 8 import org.springframework.web.socket.CloseStatus; 9 import org.springframework.web.socket.TextMessage; 10 import org.springframework.web.socket.WebSocketHandler; 11 import org.springframework.web.socket.WebSocketMessage; 12 import org.springframework.web.socket.WebSocketSession; 13 14 public class WebSocketHander implements WebSocketHandler { 15 private static final Logger logger = LoggerFactory.getLogger(WebSocketHander.class); 16 17 private static final ArrayList<WebSocketSession> users = new ArrayList<>(); 18 19 //初次链接成功执行 20 @Override 21 public void afterConnectionEstablished(WebSocketSession session) throws Exception { 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 @Override 32 public void handleMessage(WebSocketSession session, WebSocketMessage<?> webSocketMessage) throws Exception { 33 String clientName = (String) session.getHandshakeAttributes().get("WEBSOCKET_USERNAME"); 34 35 clientName = "<a onclick='changeChater(this)'>" + clientName + "</a>"; 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 @Override 52 public void handleTransportError(WebSocketSession webSocketSession, Throwable throwable) throws Exception { 53 if(webSocketSession.isOpen()){ 54 webSocketSession.close(); 55 } 56 logger.debug("链接出错,关闭链接......"); 57 users.remove(webSocketSession); 58 } 59 60 @Override 61 public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) throws Exception { 62 logger.debug("链接关闭......" + closeStatus.toString()); 63 users.remove(webSocketSession); 64 } 65 66 @Override 67 public boolean supportsPartialMessages() { 68 return false; 69 } 70 71 /** 72 * 给所有在线用户发送消息 73 * 74 * @param message 75 */ 76 public void sendMessageToUsers(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 * @param userName 92 * @param message 93 */ 94 public void sendMessageToUser(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 package com.lee.websocket.entity; 2 3 public class Person { 4 5 private int age; 6 private String name; 7 private String sex; 8 9 public int getAge() {10 return age;11 }12 public void setAge(int age) {13 this.age = age;14 }15 public String getName() {16 return name;17 }18 public void setName(String name) {19 this.name = name;20 }21 public String getSex() {22 return sex;23 }24 public void setSex(String sex) {25 this.sex = sex;26 }27 28 }
chat.jsp
1 <%@ page contentType="text/html; charset=utf-8" language="java" %> 2 <html> 3 <head lang="en"> 4 <meta charset="UTF-8"> 5 <script src='/images/loading.gif' data-original="http://cdn.sockjs.org/sockjs-0.3.min.js"></script> 6 <!-- 新 Bootstrap 核心 CSS 文件 --> 7 <link rel="stylesheet" href="http://www.cnblogs.com///cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css"> 8 <!-- 可选的Bootstrap主题文件(一般不用引入) --> 9 <link rel="stylesheet" href="http://www.cnblogs.com///cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap-theme.min.css"> 10 <!-- jQuery文件。务必在bootstrap.min.js 之前引入 --> 11 <script src='/images/loading.gif' data-original="http://www.cnblogs.com///cdn.bootcss.com/jquery/1.11.3/jquery.min.js"></script> 12 <!--<script type="text/javascript" src='/images/loading.gif' data-original="js/jquery-1.7.2.js"></script>--> 13 <!-- 最新的 Bootstrap 核心 JavaScript 文件 --> 14 <script src='/images/loading.gif' data-original="http://www.cnblogs.com///cdn.bootcss.com/bootstrap/3.3.5/js/bootstrap.min.js"></script> 15 <title>webSocket测试</title> 16 <script type="text/javascript"> 17 var chater; 18 19 $(function(){ 20 21 var websocket; 22 function connectServer() { 23 var clientName = $("#client_name").val(); 24 if ("WebSocket" in window) { 25 websocket = new WebSocket("ws://127.0.0.1:8080/websocket/echo?name=" + clientName); 26 } else if ("MozWebSocket" in window) { 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() + "<br/>" + 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() + "<br/>" + 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 function send(){ 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 function changeChater(e) { 83 chater = $(e).html(); 84 alert("您将和" + chater + "进行聊天..."); 85 } 86 </script> 87 88 </head> 89 <body> 90 91 <div id="tou">webSocket及时聊天Demo程序</div> 92 <div id="msg"></div> 93 <div > 94 <div > 95 <input type="text" placeholder="请输入用户名..." id="client_name"> 96 <span > 97 <button type="button" id="conncet_server">连接服务器</button> 98 </span> 99 </div>100 </div>101 102 <br/>103 104 <div >105 <div >106 <input type="text" placeholder="发送信息..." id="message"> 107 <span >108 <button type="button" id="send">发送</button>109 </span>110 </div>111 </div>112 </body>113 114 </html>
有兴趣的朋友可以关注github地址:https://github.com/leechenxiang/maven-spring-websocket-01
原标题:基于Spring 4.0 的 Web Socket
关键词:Spring