java socket udp 广播_1.Java 的屏幕广播(基于UDP),2.多线程下载器

本文介绍了如何使用Java实现基于UDP的屏幕广播,通过分割图片并利用时间戳和编号恢复完整图像。同时展示了多线程下载器的实现,支持断点续传和暂停功能,通过Properties文件存储下载进度。
摘要由CSDN通过智能技术生成

Java 的屏幕广播(基于UDP)

Java的屏幕广播,是基于UDP协议的,user datagram protocal 用户数据报协议,无连接,无顺序,不安全,但是作为发送实时数据还是十分常用的。

整个难点在于要字节制定协议,由于UDP的一个包最大不能超过64K,而一帧屏幕截图(1366*768)是肯定超过64K的,所以我们需要对所截出来的image进行分割发送。

假设我们将一张屏幕截图分割成若干个包发送出去,要构成屏幕广播,就需要不断的截图发包,接收端就肯定需要知道哪几个包是同一张图片,而在这几个包中哪个包是图片的哪一部分,便于恢复成一张完整的图片。

如此就需要一个协议来规定各个包之间的关系。

在下面的程序中,每张图片之间我用时间戳来区别,图片中分割的各个部分用编号来确定,还要加上每张图片所分割的数量,就构造了一个数据报包。

首先的代码是一个工具类,将byte转换成long、int,还有反转

package Boardcast;

* 用于存放byte转换成long,int的工具代码

public class Utils {

public static byte[] long2Byte(long number) {

byte[] b = new byte[8];

for(int i=0; i<8; i++) {

b[i] = (byte) (number>>((8-i-1)*8));

}

return b;

}

* 从offset开始往后的8个字节转换为long数据

public static long byte2Long(byte[] b, int offset) {

long end = 0;

for(int i=0; i<8; i++) {

end = end | ((long)(b[i+offset] & 0xff)<

* 其中的long类型转换一定要加上,如果没加上结果就成了int类型

}

return end;

}

public static byte[] int2Byte(int number) {

byte[] b = new byte[4];

b[0] = (byte) (number >> 24);

b[1] = (byte) (number >> 16);

b[2] = (byte) (number >> 8);

b[3] = (byte)number;

return b;

}

public static int byte2Int(byte[] b, int offset) {

int i3 = (b[0+offset] & 0xFF)<< 24;

int i2 = (b[1+offset] & 0xFF)<< 16;

int i1 = (b[2+offset] & 0xFF)<< 8;

int i0 = b[3+offset] & 0xFF;

return i3 | i2 | i1 | i0;

}

}

下面是广播者,发送截屏后过压缩,将压缩后的数据分割后进行发送

package Boardcast;

import java.awt.Rectangle;

import java.awt.Robot;

import java.awt.image.BufferedImage;

import java.io.ByteArrayOutputStream;

import java.net.DatagramPacket;

import java.net.DatagramSocket;

import java.net.InetSocketAddress;

import java.util.zip.ZipEntry;

import java.util.zip.ZipOutputStream;

import javax.imageio.ImageIO;

* 广播者,屏幕截图后转换成byte[]格式,过压缩,分割成一个个60K左右的小包发送出去

* 对于同一帧的图片分割出来的小包,有着相同的时间戳,同样的包数量,不同的编号,用于区分

public class Boardcaster {

private DatagramSocket socket;

private Robot robot;

private Rectangle rect;

public static void main(String[] args) {

Boardcaster bc = new Boardcaster();

System.out.println("开始发送数据。。。。");

bc.start();

}

public void start() {

try {

socket = new DatagramSocket(8888);

* 实例化一个Robot,用于抓图

robot = new Robot();

* 设置所抓图片的位置,长宽

rect = new Rectangle(0, 0, 1366, 768);

while(true) {

popDatagramPacket(socket);

System.out.println("发送一帧图片");

}

} catch(Exception e) {

e.printStackTrace();

}

}

* 抓图

public BufferedImage getPrintScreen() {

BufferedImage image = robot.createScreenCapture(rect);

return image;

}

* 抓图,压缩,分割发送

private void popDatagramPacket(DatagramSocket socket) {

try {

* 抓图

BufferedImage image = getPrintScreen();

* 将图写入baos

ByteArrayOutputStream baos = new ByteArrayOutputStream();

ImageIO.write(image, "jpg", baos);

System.out.println("未压缩的byte[]大小 = " + baos.toByteArray().length);

* 过压缩

byte[] buffer = compressImage(baos.toByteArray());

System.out.println("过压缩的byte[]大小 = " + buffer.length);

* 分割图片并发送出去

cutImageByteAndPost(buffer, socket);

} catch (Exception e) {

e.printStackTrace();

}

}

* 将image的byte[]过压缩,返回压缩后的byte[]

private byte[] compressImage(byte[] buffer) throws Exception {

* 新建一个baos,用于存放转压缩后的byte[]数据

ByteArrayOutputStream baos = new ByteArrayOutputStream();

ZipOutputStream zos = new ZipOutputStream(baos);

ZipEntry entry = new ZipEntry("image.jpg");

* 放入条目

zos.putNextEntry(entry);

* 写入数据

zos.write(buffer);

zos.close();

baos.close();

return baos.toByteArray();

}

* 将数据的byte[]分割发送出去,同一帧的图片分割成的小包,有着相同的时间戳,同样的包数量,不同的编号

* 每一个小包,开始8个字节存放时间戳,接下来四个字节存放本帧图片所分割出来的包数量,再放入四个字节的编号

public void cutImageByteAndPost(byte[] src, DatagramSocket socket) {

try {

int len = src.length;

* 分割的包数量

int count = len/60/1024;

if(len > count*60*1024) {

count++;

}

System.out.println("len = " + len + ", count = " + count);

byte[] buffer = new byte[60*1024+8+4+4];

long time = System.nanoTime();

* 发count数量的包

for(int i=0; i

* 如果是最后一个包,就将剩下的所有数据都发送出去

if(i == count-1) {

buffer = new byte[len%(60*1024)+16];

}

* 写入时间戳

System.arraycopy(Utils.long2Byte(time), 0, buffer, 0, 8);

* 写入分割的数量

System.arraycopy(Utils.int2Byte(count), 0, buffer, 8, 4);

* 写入当前的编号,从0开始

System.arraycopy(Utils.int2Byte(i), 0, buffer, 12, 4);

* 写入image内容

System.arraycopy(src, i*60*1024, buffer, 16, buffer.length-16);

System.out.println("i = " + (i) + ", buffer.length = " + buffer.length);

* 发送数据,组装成数据报包

DatagramPacket pack = new DatagramPacket(buffer, buffer.length);

* 设置发送地址、端口

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值