實(shí)現(xiàn)springboot websocket同屏瀏覽功能
1,服務(wù)端:websocket screen share\jersey-server,推送給其他客戶端。
2,運(yùn)行websocketTest\client.bat,java websocket client截屏發(fā)送到服務(wù)端,客戶端代碼websocketTest\WebSocketClient.java。
3,通過瀏覽器拉取數(shù)據(jù),地址為http://ip:8080/hello 運(yùn)行順序,先啟動(dòng)服務(wù)端,再啟動(dòng)推送客戶端,最后通過瀏覽器瀏覽截屏,未實(shí)現(xiàn)客戶端關(guān)閉連接處理,因此關(guān)閉客戶端時(shí)會(huì)有異常,可以再重啟服務(wù)端和推送客戶端后重連。
4,可以調(diào)節(jié)客戶端發(fā)送截屏頻率,以及圖片壓縮質(zhì)量。
5,注意,未做優(yōu)化,本項(xiàng)目運(yùn)行時(shí)占比較網(wǎng)絡(luò)帶寬(可以通過第四步調(diào)節(jié)發(fā)送頻率和圖片壓縮質(zhì)量調(diào)節(jié)運(yùn)行時(shí)占用的網(wǎng)絡(luò)資源)
6,記得修改設(shè)置websocket服務(wù)器的連接ip
代碼下載地址
https://download.csdn.net/download/daqinzl/87976353
實(shí)現(xiàn)細(xì)節(jié):
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
?* 注解是一個(gè)類層次的注解,它的功能主要是將目前的類定義成一個(gè)websocket服務(wù)器端,
?* 注解的值將被用于監(jiān)聽用戶連接的終端訪問URL地址,客戶端可以通過這個(gè)URL來連接到WebSocket服務(wù)器端
?*/
@ServerEndpoint(value="/websocket")
@Component
public class WebSocketTest {
?? ?
?? ?private static ConcurrentHashMap<String, Session> sessions = new ConcurrentHashMap<>();
?? ?
? ? @OnOpen
? ? public void onOpen(Session session){?
? ? ?? ?System.out.println("加入連接"); ?
? ? ?? ?sessions.put(session.getId(), session);
? ? }
? ? @OnClose
? ? public void onClose(){?
? ? ?? ?System.out.println("關(guān)閉連接");
? ? ?? ?
? ? }
? ? @OnError
? ? public void onError(Session session, Throwable error){ ?
? ? ? ?System.out.println("發(fā)生錯(cuò)誤");
? ? ? ?error.printStackTrace();?
? ? ? ?//TODO
? ? }
? ? /**
? ? ?* 收到客戶端消息后調(diào)用的方法
? ? ?* @param messages 客戶端發(fā)送過來的消息
? ? ?* @param session 可選的參數(shù)
? ? ?*/
? ? @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:\"上海浦東\"}";
// ? ? ? ? ? ?//發(fā)送字符串信息的 byte數(shù)組
// ? ? ? ? ? ?ByteBuffer bf=ByteBuffer.wrap(resultStr.getBytes("utf-8"));
// ? ? ? ? ? ?session.getBasicRemote().sendBinary(bf);
? ? ? ? ? ? //發(fā)送字符串
? ? ? ? ? ? //session.getBasicRemote().sendText("測(cè)試");
? ? ? ? ?? ?//接收客戶端發(fā)來的截屏數(shù)據(jù),發(fā)送給其他客戶端
? ? ? ? ?? ?Iterator<Session> 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(); // (通過本地操作)控制鼠標(biāo)、鍵盤等實(shí)際輸入源(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<ImageWriter> 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,瀏覽器拉取數(shù)據(jù)
<html>
<head>?
</head>
<body>
? ? <input id="text" type="text"/>
? ? <button οnclick="send()">send message</button>?
? ? <div id="message"></div>
? ? <!--收到的圖片列表-->
?? ?<div id="show"><h3>image:</h3>
?? ?<img id="img" src=""/>
?? ?</div>
</body>
<script type="text/javascript">
? ? var websocket = null;
? ? //判斷當(dāng)前瀏覽器是否支持WebSocket
? ? if ('WebSocket' in window) {
? ? ? ? websocket = new WebSocket("ws://192.168.0.109:8080/websocket");
?? ??? ?//websocket默認(rèn)是傳輸字符串的,需要改為arraybuffer二進(jìn)制傳輸類型
?? ??? ?websocket.binaryType = "arraybuffer";
? ? }else {
? ? ? ? alert('當(dāng)前瀏覽器 Not support websocket')
? ? }
? ? //連接發(fā)生錯(cuò)誤的回調(diào)方法
? ? websocket.onerror = function () {
? ? ? ? setMessageInnerHTML("WebSocket connect error");
? ? };
? ? //連接成功建立的回調(diào)方法
? ? websocket.onopen = function () {
? ? ? ? setMessageInnerHTML("WebSocket connected");
? ? }
? ? //接收到消息的回調(diào)方法
? ? websocket.onmessage = function (event) {?
?? ??? ?//將接收到的二進(jìn)制數(shù)據(jù)轉(zhuǎn)為字符串
?? ??? ?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; ? ? ? ?
? ?
? ? }
? ? //連接關(guān)閉的回調(diào)方法
? ? websocket.onclose = function () {
? ? ? ? setMessageInnerHTML("WebSocket連接關(guān)閉");
? ? }
? ? //監(jiān)聽窗口關(guān)閉事件,當(dāng)窗口關(guān)閉時(shí),主動(dòng)去關(guān)閉websocket連接,防止連接還沒斷開就關(guān)閉窗口,server端會(huì)拋異常。
? ? window.onbeforeunload = function () {
? ? ? ? closeWebSocket();
? ? }
?
? ? function setMessageInnerHTML(innerHTML) {
? ? ? ? document.getElementById('message').innerHTML += innerHTML + '<br/>';
? ? }
? ? //關(guān)閉WebSocket連接
? ? function closeWebSocket() {
? ? ? ? websocket.close();
? ? }
? ? //發(fā)送消息
? ? function send() {
? ? ? ? var message = document.getElementById('text').value;?
?? ??? ?
?? ??? ?//將字符串轉(zhuǎn)換為byte數(shù)組
?? ??? ?var bytesArr= stringToByte(message); ??
?? ??? ?var bytes =new Uint8Array(bytesArr.length) ;
?? ??? ?for (var i = 0; i < bytes.length; i++) {
?? ??? ??? ?bytes[i]=bytesArr[i];
?? ??? ?} ?
?? ??? ?console.log(bytes)
? ? ? ?websocket.send(bytes);
? ? }
?? ?
?? ?
?? ??? ?//將字符串轉(zhuǎn)為 Array byte數(shù)組
?? ??? ?function stringToByte(str) { ?
?? ??? ??? ? ? ?var bytes = new Array(); ?
?? ??? ??? ? ? ?var len, c; ?
?? ??? ??? ? ? ?len = str.length; ?
?? ??? ??? ? ? ?for(var i = 0; i < len; i++) { ?
?? ??? ??? ? ? ? ? ?c = str.charCodeAt(i); ?
?? ??? ??? ? ? ? ? ?if(c >= 0x010000 && c <= 0x10FFFF) { ?
?? ??? ??? ? ? ? ? ? ? ?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 <= 0x00FFFF) { ?
?? ??? ??? ? ? ? ? ? ? ?bytes.push(((c >> 12) & 0x0F) | 0xE0); ?
?? ??? ??? ? ? ? ? ? ? ?bytes.push(((c >> 6) & 0x3F) | 0x80); ?
?? ??? ??? ? ? ? ? ? ? ?bytes.push((c & 0x3F) | 0x80); ?
?? ??? ??? ? ? ? ? ?} else if(c >= 0x000080 && c <= 0x0007FF) { ?
?? ??? ??? ? ? ? ? ? ? ?bytes.push(((c >> 6) & 0x1F) | 0xC0); ?
?? ??? ??? ? ? ? ? ? ? ?bytes.push((c & 0x3F) | 0x80); ?
?? ??? ??? ? ? ? ? ?} else { ?
?? ??? ??? ? ? ? ? ? ? ?bytes.push(c & 0xFF); ?
?? ??? ??? ? ? ? ? ?} ?
?? ??? ??? ? ? ?} ?
?? ??? ??? ? ? ?return bytes; ?
?? ?
?? ?
?? ??? ??? ?}
?? ??? ??? ?
?? ??? ??? ?//byte數(shù)組轉(zhuǎn)字符串
?? ??? ??? ?function byteToString(arr) {
?? ??? ??? ??? ?if(typeof arr === 'string') {
?? ??? ??? ??? ??? ?return arr;
?? ??? ??? ??? ?}
?? ??? ??? ??? ?var str = '',
?? ??? ??? ??? ??? ?_arr = arr;
?? ??? ??? ??? ?for(var i = 0; i < _arr.length; 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 < bytesLength; 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.zghlxwxcb.cn/news/detail-515383.html
?? ?
</script>
</html>文章來源地址http://www.zghlxwxcb.cn/news/detail-515383.html
到了這里,關(guān)于springboot websocket 屏幕共享的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!