WebSocket协议是H5的一个基于TCP的新协议。WebSocket协议被设计来取代用HTTP作为传输层的双向通讯技术,这些技术只能牺牲其中一方来提高另一方的效率和可依赖性。
效果展示
优点
在实现websocket连线过程中,需要通过浏览器发出websocket连线请求,然后服务器发出回应,这个过程通常称为“握手” 。在 WebSocket API,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。在此WebSocket 协议中,为我们实现即时服务带来了两大好处:
1. Header互相沟通的Header是很小的-大概只有 2 Bytes
2. Server Push服务器的推送,服务器不再被动的接收到浏览器的请求之后才返回数据,而是在有新数据时就主动推送给浏览器。
应用
WebSocket可以解决很多需要实时通讯的问题,比如:聊天功能、社交订阅、股票基金变动、体育实况更新等等,都可以采用websocket进行解决。
协议内容
其中:
Upgrade: websocket Connection: Upgrade
这等于告诉web服务器,发起的请求是Websocket协议的,要用Websocket协议方式来处理请求。在请求头里,还增加了:
Sec-WebSocket-Key: p+uL7rm/spX33U/iZ/yeZg== Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits Sec-WebSocket-Version: 13
- Sec-WebSocket-Key 是一个Base64 encode的值,这个是浏览器随机生成的,告诉服务器:验证是不是真的是Websocket助理;
- Sec-WebSocket-Extensions: 扩展参数;
- Sec-WebSocket-Version 是告诉服务器所使用的Websocket Draft(协议版本)
聊天室编写
1、环境搭建
IDEA + MAVEN + JDK1.8 + Tomcat7,主要的jar包依赖如下:
<!-- Tomcat has it, so no need to package into the war file -->
<dependency>
<groupId> javax .websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>${websocket.version}</version>
<scope>provided</scope>
</dependency>
<!-- Sevlet jars for compilation, provided by Tomcat -->
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-servlet-api</artifactId>
<version>${tomcat.version}</version>
<scope>provided</scope>
</dependency>
<!-- Used to serialize the message from the browser -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.40</version>
</dependency>
2、前端js编写
思路:当用户点击登录时,使用websocket协议自动连接后台,大致流程如下:
官网地址:
客户端的流程:
- 创建Websocket实例:
- var ws = new WebSocket(“ws://127.0.0.1:8080/chat”);
a. 服务器IP:ws://127.0.0.1
b. 服务器端口:8080
c. 服务程序:chat
- 建立连接后回调函数:ws.onopen = function (event){}
- 收到服务端消息后回调函数:ws.onmessage = function(event){}
- 关闭连接后回调函数:ws.onclose = function(event){}
- 连接错误后回调函数:ws.onerror = function(event)
- 发送数据:ws.send(‘服务器,您好’);
- 查看当前连接状态:alert(ws.readyState)
var websocket, name; // 建立连接 function connection() { name = $("#name").val(); if (name == null || name. trim ().length === 0) { return; } $("#username-page").addClass("hidden"); $("#chat-page").removeClass("hidden"); //判断当前浏览器是否支持WebSocket if('WebSocket' in window){ websocket = new WebSocket("ws://127.0.0.1:8080/chat"); }else{ alert('Not support websocket'); return; } // 连接成功回调 websocket.onopen = function (event) { play(); $("#connecting").addClass("hidden"); send('JOIN'); } //连接发生错误的回调方法 websocket.onerror = function(){ console.error("连接异常。。。") } // 接收到消息的回调方法 websocket.on message = function(event){ var text = event.data; play(); onMessageReceived(text) } //连接关闭的回调方法 websocket.onclose = function(){ console.log("连接关闭。。。"); } } // 发送消息 function send(type) { var text = $("#message").val(); if (websocket == null) { return; } if ( type == 'CHAT' && (text ==null || text.trim().length == 0)) { return; } var content = {"sender":name, content: text, type: type}; websocket.send(JSON.stringify(content)); $("#message").val(''); play(); } // 声音 function play() { var audio = new Audio("/audio/beep.wav"); audio.play(); } // 处理接收的消息 function onMessageReceived(text) { var message = JSON.parse(text); var messageElement = $('<li></li>'); if(message.type === 'JOIN' || message.type === 'LEAVE') { messageElement.addClass('event-message'); } else { messageElement.addClass('chat-message'); // 创建头像 var avatarElement = $('<i></i>'); avatarElement.html(message.sender[0]); var color = getAvatarColor(message.sender); avatarElement.css('background-color', color); messageElement.append(avatarElement); var usernameElement = $('<span></span>'); usernameElement.html(message.sender); messageElement.append(usernameElement); } var textElement = $('<p></p>'); textElement.html(message.content); messageElement.append(textElement); $('#messageArea').append(messageElement); $('#messageArea')[0].scrollTop = $('#messageArea')[0].scrollHeight; } var colors = [ '#2196F3', '#32c787', '#00BCD4', '#ff5652', '#ffc107', '#ff85af', '#FF9800', '#39bbb0' ]; // 随机获取颜色 function getAvatarColor(messageSender) { var hash = 0; for (var i = 0; i < messageSender.length; i++) { hash = 31 * hash + messageSender.charCodeAt(i); } var index = Math.abs(hash % colors.length); return colors[index]; } $(document).keydown(function(event){ if (event.keyCode == 13) { send('CHAT'); } });
3、后台Java代码编写
Java关于WebSocket API官网地址:
2011 年,IETF 将 WebSocket 协议标准化为 RFC 6455。从那时起,大多数 Web 浏览器都在实现支持 WebSocket 协议的客户端 API。而且,还开发了一些实现 WebSocket 协议的 Java 库。
@ServerEndpoint("/chat")
public class ChatEndPoint {
private static Logger logger = Logger.getLogger(ChatEndPoint.class.getName());
private static List< session > sessions = new ArrayList<>();
@OnOpen
public void onOpen (Session session, EndpointConfig config) {
logger.info("开启连接。。。");
sessions.add(session);
}
@OnMessage
public void onMessage(Session session, String text) throws IOException {
logger.info("收到消息。。。");
// 构建发送内容
ChatMessage chatMessage = JSON.parseObject(text, ChatMessage.class);
// 发送
sendMessage(chatMessage.getSender(), chatMessage.getType(), chatMessage.getContent());
// 把用户存入property
Map<String, Object> properties = session.getUserProperties();
properties.put("name", chatMessage.getSender());
}
@OnClose
public void onClose(Session session, CloseReason reason) throws IOException {
logger.info("关闭连接,关闭原因:" + reason.getReasonPhrase());
sessions.remove(session);
Map<String, Object> properties = session.getUserProperties();
String name = (String)properties.get("name");
sendMessage(name, MessageType.LEAVE, null);
}
@OnError
public void onError(Session session, Throwable throwable) {
logger.info("异常处理:" + throwable.getMessage());
throwable.printStackTrace();
}
/**
* 消息推送
*/ private void sendMessage(String name, MessageType type, String content) {
if (type == MessageType.JOIN) {
content = name + "-加入聊天室!";
} else if (type == MessageType.LEAVE) {
content = name + "-离开聊天室!";
}
ChatMessage chatMessage = new ChatMessage();
chatMessage.setContent(content);
chatMessage.setSender(name);
chatMessage.setType(type);
for (Session session: sessions) {
if (!session.isOpen()) {
continue;
}
try {
session.getBasicRemote().sendText(JSON.toJSONString(chatMessage));
} catch (Exception e) {
e.printStackTrace();
continue;
}
}
}
}
4、执行tomcat7:run启动
如果需要完整源码,关注公众号【嗨码歌】发送【websocket源码】即可获取!
或者直接添加码歌悠悠q:1811119218,获取更多Java资料。