实现springboot websocket同屏浏览功能
1,服务端:websocket screen sharejersey-server,推送给其他客户端。
2,运行websocketTestclient.bat,java websocket client截屏发送到服务端,客户端代码websocketTestWebSocketClient.java。
3,通过浏览器拉取数据,地址为http://ip:8080/hello 运行顺序,先启动服务端,再启动推送客户端,最后通过浏览器浏览截屏,未实现客户端关闭连接处理,因此关闭客户端时会有异常,可以再重启服务端和推送客户端后重连。
4,可以调节客户端发送截屏频率,以及图片压缩质量。
5,注意,未做优化,本项目运行时占比较网络带宽(可以通过第四步调节发送频率和图片压缩质量调节运行时占用的网络资源)
6,记得修改设置websocket服务器的连接ip
代码下载地址
https://download.csdn.net/download/daqinzl/87976353
实现细节:
1,springboot websocket server enable
WebSocketConfig.java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
2, websocket server handler
import org.springframework.stereotype.Component;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
/**
* @ServerEndpoint
* 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,
* 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
*/
@ServerEndpoint(value=”/websocket”)
@Component
public class WebSocketTest {
private static ConcurrentHashMap sessions = new ConcurrentHashMap();
@OnOpen
public void onOpen(Session session){
System.out.println(“加入连接”);
sessions.put(session.getId(), session);
}
@OnClose
public void onClose(){
System.out.println(“关闭连接”);
}
@OnError
public void onError(Session session, Throwable error){
System.out.println(“发生错误”);
error.printStackTrace();
//TODO
}
/**
* 收到客户端消息后调用的方法
* @param messages 客户端发送过来的消息
* @param session 可选的参数
*/
@OnMessage(maxMessageSize = 5000000)
public void onMessage(byte[] messages, Session session) {
try {
//System.out.println(“接收到消息:”+new String(messages,”utf-8”));
//返回信息
// String resultStr=”{name:”张三”,age:18,addr:”上海浦东”}”;
// //发送字符串信息的 byte数组
// ByteBuffer bf=ByteBuffer.wrap(resultStr.getBytes(“utf-8”));
// session.getBasicRemote().sendBinary(bf);
//发送字符串
//session.getBasicRemote().sendText(“测试”);
//接收客户端发来的截屏数据,发送给其他客户端
Iterator it = sessions.values().iterator();
while(it.hasNext()) {
Session tsession = it.next();
if(tsession.getId()!=session.getId()) {
int len = messages.length;
int xx=0;
ByteBuffer bf=ByteBuffer.wrap(messages);
tsession.getBasicRemote().sendBinary(bf);
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
3, websocket客户端
3.1 WebSocketClient
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
//连接成功
//tomcat-juli.jar, tomcat-util.jar, tomcat-websocket.jar, websocket-api.jar
public class WebSocketClient {
public static void main(String[] args) {
try {
// String urlstr = “ws://localhost:8080/websocket”;
String urlstr = “ws://192.168.0.109:8080/websocket”;
final WebsocketClientEndpoint clientEndPoint = new WebsocketClientEndpoint(new URI(urlstr));
// add listener
clientEndPoint.addMessageHandler(new WebsocketClientEndpoint.MessageHandler() {
public void handleMessage(String message) {
System.out.println(message);
}
});
while(true)
{
try {
Thread.sleep(30);
byte[] bytes = Util.captureScreen();
ByteBuffer bf=ByteBuffer.wrap(bytes);
clientEndPoint.sendMessage(bf);
}
catch(Exception ex) {
ex.printStackTrace();
}
}
// clientEndPoint.close();
}
// catch (InterruptedException ex) {
// System.err.println(“InterruptedException exception: ” + ex.getMessage());
// }
catch (URISyntaxException ex) {
ex.printStackTrace();
System.err.println(“URISyntaxException exception: ” + ex.getMessage());
}
}
}
3.2 WebsocketClientEndpoint
import java.net.URI;
import java.nio.ByteBuffer;
import javax.websocket.ClientEndpoint;
import javax.websocket.CloseReason;
import javax.websocket.ContainerProvider;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;
/**
* ChatServer Client
*
* @author Jiji_Sasidharan
*/
@ClientEndpoint
public class WebsocketClientEndpoint {
Session userSession = null;
private MessageHandler messageHandler;
public WebsocketClientEndpoint(URI endpointURI) {
try {
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
container.connectToServer(this, endpointURI);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Callback hook for Connection open events.
*
* @param userSession the userSession which is opened.
*/
@OnOpen
public void onOpen(Session userSession) {
System.out.println(“opening websocket”);
this.userSession = userSession;
}
/**
* Callback hook for Connection close events.
*
* @param userSession the userSession which is getting closed.
* @param reason the reason for connection close
*/
@OnClose
public void onClose(Session userSession, CloseReason reason) {
System.out.println(“closing websocket”);
this.userSession = null;
}
/**
* Callback hook for Message Events. This method will be invoked when a client send a message.
*
* @param message The text message
*/
@OnMessage
public void onMessage(String message) {
if (this.messageHandler != null) {
this.messageHandler.handleMessage(message);
}
System.out.println(“receive :” + message);
}
public void close(){
onClose(userSession, new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, “normal close”));
}
/**
* register message handler
*
* @param msgHandler
*/
public void addMessageHandler(MessageHandler msgHandler) {
this.messageHandler = msgHandler;
}
/**
* Send a message.
*
* @param message
*/
public void sendMessage(String message) {
this.userSession.getAsyncRemote().sendText(message);
}
public void sendMessage(ByteBuffer message) {
this.userSession.getAsyncRemote().sendBinary(message);
}
/**
* Message handler.
*
* @author Jiji_Sasidharan
*/
public static interface MessageHandler {
public void handleMessage(String message);
}
}
3.3 截屏工具类
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Iterator;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
public class Util {
private static Robot ro = null;
private static BufferedImage bi = null;
private static Dimension di = null;
private static Rectangle rec = null;
static {
try {
ro = new Robot(); // (通过本地操作)控制鼠标、键盘等实际输入源(java.awt)
Toolkit tk = Toolkit.getDefaultToolkit(); // AWT组件的抽象父类(java.awt)
di = tk.getScreenSize();
rec = new Rectangle(0, 0, di.width, di.height);
} catch (Exception e) {
// logger.error(“screensyncserver”, e);
e.printStackTrace();
}
}
public static byte[] captureScreen() {
byte[] bytes = null;
try {
bi = ro.createScreenCapture(rec);
BufferedImage get = bi.getSubimage(0, 0, di.width, di.height);
// 从截屏中读取
bytes = imageToBytes(get);
return bytes;
} catch (Exception e) {
//logger.error(“getscreenandsend”, e);
e.printStackTrace();
}
return null;
}
private static byte[] imageToBytes(BufferedImage bImage) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
//ImageIO.write(bImage, “jpg”, out);
ImageOutputStream ios = ImageIO.createImageOutputStream(out); //var7
Iterator iter = ImageIO.getImageWritersByFormatName(“jpeg”);
ImageWriter writer = iter.next();
ImageWriteParam iwp = writer.getDefaultWriteParam();
iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
// iwp.setCompressionQuality(1.0f);
iwp.setCompressionQuality(0.3f);//TODO
writer.setOutput(ios);
writer.write(null, new IIOImage(bImage,null,null),iwp);
writer.dispose();
} catch (IOException e) {
e.printStackTrace();
//log.error(e.getMessage());
}
byte[] ret = out.toByteArray();
try {
out.close();
} catch (IOException e) {
// logger.error(“image2bytes”, e);
e.printStackTrace();
}
return ret;
}
}
4,浏览器拉取数据
image:
var websocket = null;
//判断当前浏览器是否支持WebSocket
if (‘WebSocket’ in window) {
websocket = new WebSocket(“ws://192.168.0.109:8080/websocket”);
//websocket默认是传输字符串的,需要改为arraybuffer二进制传输类型
websocket.binaryType = “arraybuffer”;
}else {
alert(‘当前浏览器 Not support websocket’)
}
//连接发生错误的回调方法
websocket.onerror = function () {
setMessageInnerHTML(“WebSocket connect error”);
};
//连接成功建立的回调方法
websocket.onopen = function () {
setMessageInnerHTML(“WebSocket connected”);
}
//接收到消息的回调方法
websocket.onmessage = function (event) {
//将接收到的二进制数据转为字符串
document.getElementById(“img”).src=””;
var uInt8Array = new Uint8Array(event.data)
var i = uInt8Array.length;
var binaryString = new Array(i);
while (i–)
{
binaryString[i] = String.fromCharCode(uInt8Array[i]);
}
var data = binaryString.join(”);
var base64 = window.btoa(data);
//if(src.endsWith(“jpeg”))
var url=”data:image/jpeg;base64,” + base64;
//else if(src.endsWith(“gif”))
//var url=”data:image/gif;base64,” + base64;
var img = document.getElementById(“img”);
img.src=url;
img.height=1080;
img.width=1920;
}
//连接关闭的回调方法
websocket.onclose = function () {
setMessageInnerHTML(“WebSocket连接关闭”);
}
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function () {
closeWebSocket();
}
function setMessageInnerHTML(innerHTML) {
document.getElementById(‘message’).innerHTML += innerHTML + ‘
‘;
}
//关闭WebSocket连接
function closeWebSocket() {
websocket.close();
}
//发送消息
function send() {
var message = document.getElementById(‘text’).value;
//将字符串转换为byte数组
var bytesArr= stringToByte(message);
var bytes =new Uint8Array(bytesArr.length) ;
for (var i = 0; i
bytes[i]=bytesArr[i];
}
console.log(bytes)
websocket.send(bytes);
}
//将字符串转为 Array byte数组
function stringToByte(str) {
var bytes = new Array();
var len, c;
len = str.length;
for(var i = 0; i c = str.charCodeAt(i);
if(c >= 0x010000 && c bytes.push(((c >> 18) & 0x07) | 0xF0);
bytes.push(((c >> 12) & 0x3F) | 0x80);
bytes.push(((c >> 6) & 0x3F) | 0x80);
bytes.push((c & 0x3F) | 0x80);
} else if(c >= 0x000800 && c bytes.push(((c >> 12) & 0x0F) | 0xE0);
bytes.push(((c >> 6) & 0x3F) | 0x80);
bytes.push((c & 0x3F) | 0x80);
} else if(c >= 0x000080 && c bytes.push(((c >> 6) & 0x1F) | 0xC0);
bytes.push((c & 0x3F) | 0x80);
} else {
bytes.push(c & 0xFF);
}
}
return bytes;
}
//byte数组转字符串
function byteToString(arr) {
if(typeof arr === ‘string’) {
return arr;
}
var str = ”,
_arr = arr;
for(var i = 0; i
var one = _arr[i].toString(2),
v = one.match(/^1+?(?=0)/);
if(v && one.length == 8) {
var bytesLength = v[0].length;
var store = _arr[i].toString(2).slice(7 – bytesLength);
for(var st = 1; st
store += _arr[st + i].toString(2).slice(2);
}
str += String.fromCharCode(parseInt(store, 2));
i += bytesLength – 1;
} else {
str += String.fromCharCode(_arr[i]);
}
}
return str;
}
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
相关推荐: [线段树] HDOJ Excited Database
把一个矩阵化成3个三角形容斥,然后用等差线段树就可以做了... #include using namespace std; typedef long long LL; #define now o, L, R, tree #define lson o > …