众所周知,Web 应用的交互过程通常是客户端通过浏览器发出一个请求,服务器端接收请求后进行处理并返回结果给客户端,客端浏览器将信息呈现。但是对于实时性要求较高、海量并发的应用,比如金融证券的实时信息,web导航应用中地理位置获取,社交网络的实时消息推送等。

方案一:轮询,客户端用js代码每隔一定时间向服务器发送请求,这样会造成资源浪费(浪费带宽),在高并发的情况下还可能造成服务器奔溃。

方案二:基于Flash、AdobeFlash,通过socket实现数据信息交互,再利用Flash暴露的接口供js调用,但是Flash在移动互联网上的支持不好,IOS和Android都不支持Flash了。

方案三:WebSocket,2014年开始,各大应用服务器和浏览器厂商逐步统一,J2EE7也实现了WebSocket协议,无论客户端还是服务器都提供了对其的支持。

WebSocket介绍与原理

WebSocket 是 HTML5 一种新的协议。它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯,它建立在 TCP 之上,同 HTTP 一样通过 TCP 来传输数据,但是它和HTTP

最大不同是:

WebSocket 是一种双向通信协议,在基于http建立连接后,WebSocket 服务器和 browser都能主动向对方发送或接收数据,就像 Socket 一样;WebSocket 需要类似 TCP 的客户端和服务器端通过握手连接,连接成功后才能相互通信,实现长连接。

WebSocket 客户端连接报文

GET /webfin/websocket/ HTTP/1.1

Host: localhost

Upgrade: websocket

Connection: Upgrade

Sec-WebSocket-Key: xqBt3ImNzJbYqRINxEFlkg==

Origin: http://localhost:8080

Sec-WebSocket-Version: 13

可以看到,客户端发起的 WebSocket 连接报文类似传统 HTTP 报文,”Upgrade:websocket”参数值表明这是 WebSocket 类型请求,“Sec-WebSocket-Key”是 WebSocket 客户端发送的一个 base64 编码的密文,要求服务端必须返回一个对应加密的“Sec-WebSocket-Accept”应答,否则客户端会抛出“Error

during WebSocket handshake”错误,并关闭连接。

WebSocket 服务端响应报文

HTTP/1.1 101 Switching Protocols

Upgrade: websocket

Connection: Upgrade

Sec-WebSocket-Accept: K7DJLdLooIwIG/MOpvWFB3y3FE8=

“Sec-WebSocket-Accept”的值是服务端采用与客户端一致的密钥计算出来后返回客户端的,“HTTP/1.1 101 Switching Protocols”表示服务端接受 WebSocket 协议的客户端连接,经过这样的请求-响应处理后,客户端服务端的 WebSocket 连接握手成功, 后续就可以进行

TCP 通讯了。

---------------------

作者:zhengholien

来源:CSDN

原文:https://blog.csdn.net/zhengholien/article/details/76696509?utm_source=copy

版权声明:本文为博主原创文章,转载请附上博文链接!

项目实例

采用spring maven项目,开发工具eclise ,tomcat 版本8.5以上(不需要引用其它jar包)

主要jar包要求:

6989f7fbb23aa6816da2a9336f352da5.png(tomcat8.5 以上不需要引包)

代码实例

cbe743c8a0886e6ce99135fd0b8e001c.png

websocket核心配置类

packagecontroller;importjava.util.Set;importjavax.websocket.Endpoint;importjavax.websocket.server.ServerApplicationConfig;importjavax.websocket.server.ServerEndpointConfig;/*** websockket 核心配置类,项目启动时会自动启动,类似与ContextListener.*/

public class WebSocketConfig implementsServerApplicationConfig{/*** 注解方式

* 扫描src下所有类@ServerEndPoint注解的类。*/

public Set> getAnnotatedEndpointClasses(Set>arg0) {

System.out.println("============="+arg0.size());//返回

returnarg0;

}/*** 获取所有以接口方式配置的webSocket类。*/

public Set getEndpointConfigs(Set>arg0) {return null;

}

}

webSocket服务器

packagecontroller;importjavax.websocket.OnClose;importjavax.websocket.OnMessage;importjavax.websocket.OnOpen;importjavax.websocket.Session;importjavax.websocket.server.PathParam;importjavax.websocket.server.ServerEndpoint;importjava.util.HashSet;importjava.util.List;importjava.util.Set;importjava.util.Map;importjava.util.concurrent.ConcurrentHashMap;importjava.util.concurrent.CopyOnWriteArraySet;/*** writer: holien

* Time: 2017-08-01 13:00

* Intent: webSocket服务器*/@ServerEndpoint("/webSocket/chat/{roomName}/{username}")public classWebSocketServer {//使用map来收集session,key为roomName,value为同一个房间的用户集合//concurrentMap的key不存在时报错,不是返回null

private static final Map> rooms = newConcurrentHashMap();private static final Map userNameList = newConcurrentHashMap();

@OnOpenpublic void connect(@PathParam("roomName") String roomName,@PathParam("username") String username, Session session) throwsException {//将session按照房间名来存储,将各个房间的用户隔离

if (!rooms.containsKey(roomName)) {//创建房间不存在时,创建房间

Set room = new HashSet();//添加用户

room.add(session);

rooms.put(roomName, room);

}else{//房间已存在,直接添加用户到相应的房间

rooms.get(roomName).add(session);

}

System.err.println("username"+username);

System.out.println("a client has connected!");

}

@OnClosepublic void disConnect(@PathParam("roomName") String roomName,@PathParam("userName") String userName, Session session) {

rooms.get(roomName).remove(session);

System.out.println("a client has disconnected!");

}

@OnMessagepublic void receiveMsg(@PathParam("roomName") String roomName,@PathParam("username") String username,

String msg, Session session)throwsException {//此处应该有html过滤

msg = username + ":" +msg;

System.out.println(msg);//接收到信息后进行广播

broadcast(roomName, msg);

}//按照房间名进行广播

public static void broadcast(String roomName, String msg) throwsException {for(Session session : rooms.get(roomName)) {

session.getBasicRemote().sendText(msg);

}

}

}

页面显示

网络聊天室

.msg_board{width:322px;height:100px;border:solid 1px darkcyan;padding:5px;overflow-y:scroll;// 文字长度大于div宽度时换行显示

word-break:break-all;

}

/*set srcoll start*/::-webkit-scrollbar{width:10px;height:10px;background-color:#D6F2FD;

}::-webkit-scrollbar-track{-webkit-box-shadow:inset 0 0 6px rgba(0,0,0,0.3);

/*border-radius: 5px;*/background-color:#D6F2FD;

}::-webkit-scrollbar-thumb{height:20px;

/*border-radius: 10px;*/-webkit-box-shadow:inset 0 0 6px rgba(0,0,0,.3);background-color:#89D7F7;

}

/*set srcoll end*/

房间名

用户名

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐