屏幕广播
1、服务器端
1 public class ThreadMain { 2 3 public static void main(String[] args) { 4 new ServerSender().start(); 5 } 6 7 } 8 9 10 public class ServerSender { 11 //UDP套接字 12 private DatagramSocket socket; 13 //创建机器人,抓图 14 private Robot robot; 15 private Rectangle rect; 16 public ServerSender() { 17 try { 18 socket=new DatagramSocket(8888); 19 robot=new Robot(); 20 rect=new Rectangle(0, 0, 1366, 768); 21 } catch (Exception e) { 22 e.printStackTrace(); 23 } 24 } 25 public void start(){ 26 int i=0; 27 while(true){ 28 sendOneScreen(); 29 } 30 } 31 private void sendOneScreen() { 32 //1.抓取一屏幕 33 byte[] frameData=catchOneScreen(true); 34 //2.切割 35 List<FrameUnit> units=splitScreen(frameData); 36 //3.组装内容,并发送所有帧单元 37 sendAllUnits(units); 38 } 39 //发送所有帧单元 40 private void sendAllUnits(List<FrameUnit> units){ 41 for (FrameUnit unit:units) { 42 //处理帧单元 43 DatagramPacket pack=processUnit(unit); 44 try { 45 socket.send(pack); 46 } catch (IOException e) { 47 e.printStackTrace(); 48 } 49 } 50 } 51 //处理帧单元 52 private DatagramPacket processUnit(FrameUnit unit){ 53 byte[] buf=new byte[unit.getLength()+14]; 54 //时间戳 55 byte[] timeBytes=bytesUtil.long2ByteArr(unit.getTimestamp()); 56 System.arraycopy(timeBytes, 0, buf, 0, 8); 57 //count 58 buf[8]=(byte) unit.getCount(); 59 //index 60 buf[9]=(byte) unit.getIndex(); 61 //data长度 62 byte[] unitLengBytes=bytesUtil.int2ByteArr(unit.getLength()); 63 System.arraycopy(unitLengBytes, 0, buf, 10, 4); 64 //数据 65 byte[] unitDataBytes=unit.getUnitData(); 66 System.arraycopy(unitDataBytes, 0, buf, 14, unitDataBytes.length); 67 //设置数据报包的广播地址 68 DatagramPacket pack=new DatagramPacket(buf, buf.length); 69 InetSocketAddress addr=new InetSocketAddress("localhost", 9999); 70 pack.setSocketAddress(addr); 71 return pack; 72 73 } 74 //切屏 75 private List<FrameUnit> splitScreen(byte[] frameData) { 76 //frameUnit的长度 77 int unitLength=60*1024; 78 //帧单元集合 79 List<FrameUnit> list = new ArrayList<>(); 80 int count=0; 81 //正好整除unit大小 82 if(frameData.length % unitLength==0){ 83 count=frameData.length / unitLength; 84 } 85 else{ 86 count=frameData.length / unitLength +1; 87 } 88 //取出时间戳 89 long timestamp=System.currentTimeMillis(); 90 for(int i=0;i<count;i++){ 91 FrameUnit unit = new FrameUnit(); 92 unit.setTimestamp(timestamp); 93 unit.setCount(count); 94 unit.setIndex(i); 95 //如果不是最后一帧单元,大小为60k; 96 if(i !=(count-1)){ 97 unit.setLength(60*1024); 98 byte[] unitData=new byte[60*1024]; 99 System.arraycopy(frameData, i*60*1024, unitData, 0, 60*1024); 100 unit.setUnitData(unitData); 101 } 102 //最后一帧处理 103 else{ 104 //取得最后一帧的长度 105 int remain=frameData.length % unitLength==0?60*1024:frameData.length % unitLength; 106 unit.setLength(remain); 107 byte[] unitData=new byte[remain]; 108 System.arraycopy(frameData, i*60*1024, unitData, 0, remain); 109 unit.setUnitData(unitData); 110 } 111 list.add(unit); 112 } 113 114 return list; 115 } 116 //抓取一屏画面 117 private byte[] catchOneScreen(boolean zip) { 118 try { 119 BufferedImage image = robot.createScreenCapture(rect); 120 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 121 ImageIO.write(image, "jpg", bos); 122 //原生数据 123 byte[] rawrate=bos.toByteArray(); 124 //需要压缩 125 if(zip){ 126 ByteArrayOutputStream bos0 = new ByteArrayOutputStream(); 127 ZipOutputStream zos=new ZipOutputStream(bos0); 128 zos.putNextEntry(new ZipEntry("0001")); 129 zos.write(rawrate); 130 zos.close(); 131 bos0.close(); 132 //直接返回该数据,后面不再执行 133 return bos0.toByteArray(); 134 } 135 return rawrate; 136 } catch (Exception e) { 137 e.printStackTrace(); 138 } 139 return null; 140 } 141 }
2、客户端
1 public class StudentMain { 2 3 public static void main(String[] args) { 4 StudentUI ui = new StudentUI(); 5 new ReceiverThread(ui).start(); 6 } 7 8 } 9 10 public class ReceiverThread extends Thread { 11 // 存放所有帧单元的集合 12 private Map<Integer, FrameUnit> map = new HashMap<>(); 13 private StudentUI ui; 14 private DatagramSocket socket; 15 16 public ReceiverThread(StudentUI ui) { 17 try { 18 this.ui = ui; 19 socket = new DatagramSocket(9999); 20 } catch (SocketException e) { 21 e.printStackTrace(); 22 } 23 } 24 25 public void run() { 26 // 数据缓存区 27 byte[] buf = new byte[60 * 1024 + 14]; 28 DatagramPacket pack = new DatagramPacket(buf, buf.length); 29 try { 30 while (true) { 31 socket.receive(pack); 32 // 解析数据报包成FrameUnit 33 FrameUnit unit = parsePack(pack); 34 // 处理帧单元 35 processUnit(unit); 36 } 37 } catch (IOException e) { 38 e.printStackTrace(); 39 } 40 } 41 42 // 解析数据包,解析帧单元 43 private FrameUnit parsePack(DatagramPacket pack) { 44 // 缓冲区数据,含有header 45 byte[] bufData = pack.getData(); 46 FrameUnit unit = new FrameUnit(); 47 // 处理时间戳 48 long timestamp = bytesUtil.byte2long(bufData); 49 unit.setTimestamp(timestamp); 50 // frameUnit个数 51 int count = bufData[8]; 52 unit.setCount(count); 53 // frame索引 54 int index = bufData[9]; 55 unit.setIndex(index); 56 // 数据长度 57 byte[] bytelength = new byte[4]; 58 System.arraycopy(bufData, 10, bytelength, 0, 4); 59 int dataLen = bytesUtil.byte2int(bytelength); 60 unit.setLength(dataLen); 61 // 图像数据处理 62 byte[] unitData = new byte[dataLen]; 63 System.arraycopy(bufData, 14, unitData, 0, dataLen); 64 unit.setUnitData(unitData); 65 return unit; 66 } 67 68 // 处理帧单元 69 private void processUnit(FrameUnit unit) { 70 // 如果集合为空,没有帧单元数据 71 if (map.isEmpty()) { 72 map.put(unit.getIndex(), unit); 73 } else { 74 // 提取map中存放的帧单元的时间戳 75 long oldTime = map.values().iterator().next().getTimestamp(); 76 long currTime = unit.getTimestamp(); 77 // 同一帧 78 if (oldTime == currTime) { 79 map.put(unit.getIndex(), unit); 80 } 81 // 新帧单元 82 else if (currTime > oldTime) { 83 map.clear(); 84 map.put(unit.getIndex(), unit); 85 } 86 // 老帧单元迟到,直接丢弃 87 else { 88 } 89 } 90 // 处理frame 91 prcessFrame(true); 92 } 93 94 // 判断是否集齐了所有帧单元,处理称为一帧 95 private void prcessFrame(boolean zip) { 96 try { 97 int count = map.values().iterator().next().getCount(); 98 int size = map.size(); 99 // 集齐了所有帧单元 100 if (count == size) { 101 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 102 for (int i = 0; i < count; i++) { 103 FrameUnit unit = map.get(i); 104 bos.write(unit.getUnitData()); 105 } 106 // 得到一屏幕画面的帧数据 107 byte[] frameData = bos.toByteArray(); 108 if (zip) { 109 ByteArrayOutputStream bos0 = new ByteArrayOutputStream(); 110 ByteArrayInputStream bis = new ByteArrayInputStream(frameData); 111 ZipInputStream zis = new ZipInputStream(bis); 112 zis.getNextEntry(); 113 byte[] buf = new byte[1024]; 114 int len = -1; 115 while ((len=zis.read(buf)) != -1) { 116 bos0.write(buf, 0, len); 117 } 118 zis.close(); 119 // 解压数据 120 frameData = bos0.toByteArray(); 121 } 122 ui.updateUI(frameData); 123 map.clear(); 124 } 125 126 } catch (Exception e) { 127 } 128 } 129 130 } 131 132 133 public class StudentUI extends JFrame{ 134 135 private static final long serialVersionUID = 2084514325030688532L; 136 //标签字段 137 private JLabel lbl; 138 public StudentUI(){ 139 init(); 140 this.setVisible(true); 141 } 142 private void init() { 143 this.setTitle("学生端"); 144 this.setLayout(null); 145 this.setBounds(0, 0, 1366, 768); 146 147 lbl=new JLabel(); 148 lbl.setBounds(0, 0, 1366, 768); 149 this.add(lbl); 150 151 this.addWindowListener(new WindowAdapter() { 152 @Override 153 public void windowClosing(WindowEvent e) { 154 System.exit(-1); 155 } 156 }); 157 } 158 //更新UI 159 public void updateUI(byte[] frameData){ 160 try { 161 ByteArrayInputStream bis = new ByteArrayInputStream(frameData); 162 BufferedImage image = ImageIO.read(bis); 163 ImageIcon icon = new ImageIcon(image); 164 lbl.setIcon(icon); 165 } catch (Exception e) { 166 } 167 168 } 169 }
3、工具类
public class bytesUtil { //字节数组转成int public static int byte2int(byte[] arr){ int i0=arr[0] & 0xff; int i1=(arr[1] & 0xff)<<8; int i2=(arr[2] & 0xff)<<16; int i3=(arr[3] & 0xff)<<24; return i0 |i1|i2|i3; } //字节数组转成long public static long byte2long(byte[] arr){ long i0=arr[0] & 0xffL; long i1=(arr[1] & 0xffL)<<8; long i2=(arr[2] & 0xffL)<<16; long i3=(arr[3] & 0xffL)<<24; long i4=(arr[4] & 0xffL)<<32; long i5=(arr[5] & 0xffL)<<40; long i6=(arr[6] & 0xffL)<<48; long i7=(arr[7] & 0xffL)<<56; return i0 | i1 | i2 | i3 | i4 | i5 | i6 | i7; } /** * 将整数转换成字节数组 */ public static byte[] int2ByteArr(int i){ byte[] bytes = new byte[4] ; bytes[0] = (byte)(i >> 0) ; bytes[1] = (byte)(i >> 8) ; bytes[2] = (byte)(i >> 16) ; bytes[3] = (byte)(i >> 24) ; return bytes ; } /** * 将长整数转换成字节数组 */ public static byte[] long2ByteArr(long i){ byte[] bytes = new byte[8] ; bytes[0] = (byte)(i >> 0) ; bytes[1] = (byte)(i >> 8) ; bytes[2] = (byte)(i >> 16) ; bytes[3] = (byte)(i >> 24) ; bytes[4] = (byte)(i >> 32) ; bytes[5] = (byte)(i >> 40) ; bytes[6] = (byte)(i >> 48) ; bytes[7] = (byte)(i >> 56) ; return bytes ; } } public class FrameUnit { private long timestamp; private int count; private int index; private int length; private byte[] unitData; public long getTimestamp() { return timestamp; } public void setTimestamp(long timestamp) { this.timestamp = timestamp; } public int getCount() { return count; } public void setCount(int count) { this.count = count; } public int getIndex() { return index; } public void setIndex(int index) { this.index = index; } public int getLength() { return length; } public void setLength(int length) { this.length = length; } public byte[] getUnitData() { return unitData; } public void setUnitData(byte[] unitData) { this.unitData = unitData; } }