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

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
    评论
1.屏幕广播 除了原来的全屏和窗口广播模式外,增加了绑定窗口模式。老师可以选择屏幕的某个部分广播给学生,以增加教学的直观性。 2.监控转播 监控时抓取快照。老师可以在监控学生的时候,对学生画面拍快照,保存学生画面的截图。 3.班级模型管理 新增加班级模型管理按钮,并设计了单独的管理界面,实现对班级模型的统一管理。 4.屏幕录制 屏幕录制经过全面技术革新,可以直接录制成 ASF 文件,也可以用 Windows 自带的 Media Player 直接播放。 屏幕录制的音视频不再分两个文件存放,保证了录制的文件的音视频同步性。 屏幕录制可以选择质量方案,以便客户在录制的文件尺寸和质量上,根据需要取舍。 屏幕录制提示小红点闪烁,录制过程更加直观。 提供屏幕录制转换,以便早期的客户把老版本的文件转换为 ASF 文件。 5.远程设置 远程设置新增桌面主题设置,桌面背景设置,屏幕保护方案设置。 远程设置可以设置学生的频道号和音量。 远程设置可以设置学生的卸载密码,是否启用进程保护,断线锁屏,热键退出。 6.远程命令 新增可以远程关闭所有学生正在执行的应用程序。 7.分组管理 分组管理可以新建,删除,重命名分组。添加和删除分组中的成员。 分组信息随班级模型永久保存,下次上课可以直接使用保存的分组。 8.随堂小考 使用此功能,教师可以启动快速的单题考试或随堂调查,并立即给出结果。 9.系统日志 显示和自动保存系统运行过程中的关键事件,包括学生登录登出,电池电量,资源不足,提交文件等。 极域电子教室 注意事项 1.安装本产品前,如果已安装我公司以前的版本或同类软件,请先将以前版本或同类软件移除后,再进行安装。 2.安装本软件后,请一定要重新启动计算机才可使用。如果不重新启动计算机,有可能会造成本软件的某些功能不能正常使用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值