org.springframework.boot
spring-boot-starter-websocket
org.java-websocket
Java-WebSocket
1.4.0
这里采用的是springboot的内置容器,所以需要注入ServerEndpointExporter这个类,来开启websocket的支持
/**
* Author: songxiaoyan
* Description:开启WebSocket支持
* Date: Created in 14:53 2019/5/7
*/
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
这里的@ServerEndpoint类似于spring的controller层,ws协议可以从这个入口进入,另还可以携带参数
com.dxjtai.aicappk.service;
import com.dxjtai.aicappk.postcall.RecogEngine;
import org.json.JSONObject;
import org.json.XML;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* Author: songxiaoyan
* Description:websocket服务端
* Date: Created in 14:57 2019/5/7
*/
@ServerEndpoint("/websocket/{sid}")
@Component
public class MyWebSocketServer {
//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
private static int onlineCount = 0;
//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
private static CopyOnWriteArraySet<MyWebSocketServer> webSocketSet = new CopyOnWriteArraySet<MyWebSocketServer>();
//与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
//接收sid
private String sid="";
/**
* 连接建立成功调用的方法*/
@OnOpen
public void onOpen(Session session,@PathParam("sid") String sid) {
this.session = session;
webSocketSet.add(this); //加入set中
addOnlineCount(); //在线数加1
System.out.println("有新窗口开始监听:"+sid+",当前在线人数为" + getOnlineCount());
this.sid=sid;
try {
sendMessage("连接成功");
//设置传输最大字节数
session.setMaxBinaryMessageBufferSize(524280000);
session.setMaxTextMessageBufferSize(524280000);
} catch (IOException e) {
System.err.println("websocket IO异常");
}
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
webSocketSet.remove(this); //从set中删除
subOnlineCount(); //在线数减1
System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());
}
/**
* 收到客户端消息后调用的方法
*
* @param message 客户端发送过来的消息*/
@OnMessage
public void onMessage(String message, Session session) {
System.out.println("收到来自窗口"+sid+"的信息:"+message);
//群发消息
for (MyWebSocketServer item : webSocketSet) {
try {
item.sendMessage("服务器推出的消息"+message);
// sendInfo("服务器推出的消息"+message+sid,sid);
} catch (IOException e) {
e.printStackTrace();
}
}
}
@OnMessage
public void onMessage(byte[] message,Session session) throws IOException {
// saveFileFromBytes(message, "src/" + fileName);
System.out.println("进入消息接收");
// 根据自己的业务进行相应处理,我这里是要接受一个数据流,处理完返回json串。
String url = "";//根据自己业务自定义url
RecogEngine.HttpRequest request = new RecogEngine().new HttpRequest();
String response = null;
response = request.post(url, message);
JSONObject xmlJSONObj = XML.toJSONObject(response);
response = xmlJSONObj.toString();
System.out.println(response);
//调用服务端返回消息
sendMessage( response );
}
/**
*
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
System.err.println("发生错误");
error.printStackTrace();
}
/**
* 实现服务器主动推送
*/
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
/**
* 群发自定义消息
* */
public static void sendInfo(String message,@PathParam("sid") String sid) throws IOException {
System.out.println("推送消息到窗口"+sid+",推送内容:"+message);
for (MyWebSocketServer item : webSocketSet) {
try {
//这里可以设定只推送给这个sid的,为null则全部推送
if(sid==null) {
item.sendMessage(message);
}else if(item.sid.equals(sid)){
item.sendMessage(message);
}
} catch (IOException e) {
continue;
}
}
}
public static synchronized int getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
MyWebSocketServer.onlineCount++;
}
public static synchronized void subOnlineCount() {
MyWebSocketServer.onlineCount--;
}
}
这里使用的是java-websocket实现的客户端,感兴趣的话可以试着使用springboot集成的客户端
package com.dxjtai.aicappk.util;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft_6455;
import org.java_websocket.enums.ReadyState;
import org.java_websocket.handshake.ServerHandshake;
import java.io.*;
import java.net.URI;
import java.net.URISyntaxException;
/**
* Author: songxiaoyan
* Description:websocket客户端测试
* Date: Created in 17:00 2019/5/8
* Modified By:
*/
public class WebsocketClient {
public static WebSocketClient client;
private static String url = "ws://localhost:8011/websocket/33";
public static void main(String[] args) throws InterruptedException {
try {
client = new WebSocketClient(new URI(url),new Draft_6455()) {
@Override
public void onOpen(ServerHandshake serverHandshake) {
System.out.println("打开链接");
}
@Override
public void onMessage(String s) {
System.out.println("收到消息"+s);
}
@Override
public void onClose(int i, String s, boolean b) {
System.out.println("链接已关闭");
}
@Override
public void onError(Exception e) {
e.printStackTrace();
System.out.println("发生错误已关闭");
}
};
} catch (URISyntaxException e) {
e.printStackTrace();
}
client.connect();
System.out.println(client.getDraft());
while(!client.getReadyState().equals(ReadyState.OPEN)){
System.out.println("正在连接");
}
System.out.println("打开了");
try {
String filename = "C:\\Users\\knowologe\\Desktop\\8k16bit.wav";
byte[] data=InputStream2ByteArray(filename);
// for(int i=0;i<5;i++){
client.send(data);
// Thread.sleep(1000);
// }
} catch (Exception e) {
e.printStackTrace();
}
// client.close();
}
public static void send(byte[] bytes){
client.send(bytes);
}
private static byte[] InputStream2ByteArray(String filePath) throws IOException {
InputStream in = new FileInputStream(filePath);
byte[] data = toByteArray(in);
in.close();
return data;
}
private static byte[] toByteArray(InputStream in) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buffer = new byte[1024 * 4];
int n = 0;
while ((n = in.read(buffer)) != -1) {
out.write(buffer, 0, n);
}
return out.toByteArray();
}
}
<!DOCTYPE html>
<html>
<head>
<title>WebSocket Chat Client</title>
<meta charset="utf-8" />
<script src="http://code.jquery.com/jquery-1.6.4.min.js"></script>
<script type="text/javascript" >
//判读浏览器是否支持websocket
$().ready(function() {
if ( !window.WebSocket ) {
alert("童鞋, 你的浏览器不支持该功能啊");
}
});
//在消息框中打印内容
function log(text) {
$("#log").append(text+"\n");
}
//全局的websocket变量
var ws;
//创建连接
$(function() {
$("#uriForm").submit(function() {
log("准备连接到" + $("#uri").val());
ws = new WebSocket($("#uri").val());
//连接成功建立后响应
ws.onopen = function() {
log("成功连接到" + $("#uri").val());
}
//收到服务器消息后响应
ws.onmessage = function(e) {
log("收到服务器消息:" + e.data + "'\n");
}
//连接关闭后响应
ws.onclose = function() {
log("关闭连接");
$("#disconnect").attr({"disabled":"disabled"});
$("#uri").removeAttr("disabled");
$("#connect").removeAttr("disabled");
ws = null;
}
$("#uri").attr({"disabled":"disabled"});
$("#connect").attr({"disabled":"disabled"});
$("#disconnect").removeAttr("disabled");
return false;
});
});
//发送字符串消息
$(function() {
$("#sendForm").submit(function() {
if (ws) {
var textField = $("#textField");
ws.send(textField.val());
log("我说:" + textField.val());
textField.val("");
textField.focus();
}
return false;
});
});
//发送arraybuffer(二进制文件)
$(function() {
$("#sendFileForm").submit(function() {
var inputElement = document.getElementById("file");
var fileList = inputElement.files;
for ( var i = 0; i < fileList.length; i++) {
console.log(fileList[i]);
log(fileList[i].name);
//发送文件名
ws.send(fileList[i].name);
// reader.readAsBinaryString(fileList[i]);
//读取文件
var reader = new FileReader();
reader.readAsArrayBuffer(fileList[i]);
// reader.readAsText(fileList[i]);
//文件读取完毕后该函数响应
reader.onload = function loaded(evt) {
var binaryString = evt.target.result;
// Handle UTF-16 file dump
log("\n开始发送文件");
ws.send(binaryString);
}
}
return false;
});
});
$(function() {
$("#disconnect").click(function() {
if (ws) {
$("#log").empty();
ws.close();
ws = null;
}
return false;
});
});
$(function() {
$("#reset").click(function() {
$("#log").empty();
return false;
});
});
</script>
</head>
<body>
<form id="uriForm">
<input type="text" id="uri" value="ws://localhost:8011/websocket/33"
style="width: 200px;"> <input type="submit" id="connect"
value="Connect"><input type="button" id="disconnect"
value="Disconnect" disabled="disabled">
</form>
<br>
<form id="sendFileForm">
<input id="file" type="file" multiple />
<input type="submit" value="Send" />
<input type="button" id="reset" value="清空消息框"/>
</form>
<br>
<form id="sendForm">
<input type="text" id="textField" value="" style="width: 200px;">
<input type="submit" value="Send">
</form>
<br>
<form>
<textarea id="log" rows="30" cols="100"
style="font-family: monospace; color: red;"></textarea>
</form>
<br>
</body>
</html>
需要在nginx.config中配置
开始未加入协议转换头文件的设置,导致不能识别ws协议,一直认为是个http协议,报错GET /websocket/33 HTTP/1.1" 404 144 “-” “-”
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection “upgrade”;
server {
listen 8080;
server_name 域名;
location / {
proxy_pass http://127.0.0.1:8011/; // 代理转发地址
proxy_http_version 1.1;//http的版本号
proxy_read_timeout 3600s; // 超时设置,默认为60s
// 启用支持websocket连接,必须设置,主要讲http协议转化为ws协议
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
最近公司需要用到websocket全双工通信处理消息,经过各种跳坑,总算成功完成。非常感谢网上各位大牛分享的博客,帮助了我很多,欢迎各位小伙伴一起探讨研究哦!
另,如有侵权,请联系本人删除!
参考博客资料:
https://blog.csdn.net/moshowgame/article/details/80275084
https://blog.csdn.net/weixin_37264997/article/details/80341911