1.QQ完成
2.使用DatagramSocket实现屏广
Server : //完善代码,区域缩小 2.合包
客户端 : JFrame ,ImageIcon
------------------------------------------------------
项目源码:
package com.it18zhang.udp.screenbroadcast;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.GZIPInputStream;
/**
* 客户端接收线程
*/
public class ClientReceiverThread extends Thread {
//存放所有frame的集合
private Map<Long, Map<Integer,FrameUnit>> frames = new HashMap<Long,Map<Integer,FrameUnit>>();
// 客户端窗口
private ClientUI ui;
private DatagramSocket sock;
public ClientReceiverThread(ClientUI ui) {
this.ui = ui;
try {
sock = new DatagramSocket(8889);
}
catch (Exception e) {
}
}
public void run() {
try {
// 缓冲区
byte[] buf = new byte[60 * 1024];
DatagramPacket pack = new DatagramPacket(buf, buf.length);
while (true) {
//接收数据,收到了一帧画面的一个单元。
sock.receive(pack);
FrameUnit unit = new FrameUnit(pack);
//包含gid
Map<Integer,FrameUnit> old = null ;
if(frames.containsKey(unit.getGid())){
//取出原有的
old = frames.get(unit.getGid());
old.put(unit.getIndex(), unit);
}
//不包含
else{
old = new HashMap<Integer,FrameUnit>();
old.put(unit.getIndex(), unit);
frames.put(unit.getGid(),old) ;
}
//是否收集齐全所有的FrameUnit
int count = unit.getCount() ;
int receiveCount = frames.get(unit.getGid()).size();
//齐了
if(count == receiveCount){
byte[] p_w_picpath = mergeImage(old);
ui.refreshImage(p_w_picpath);
}
}
}
catch (Exception e) {
e.printStackTrace();
}
}
/**
* 使用gzip进行解压处理
*/
public byte[] gzipDecompress(byte[] srcdata, int offset, int length) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
//
ByteArrayInputStream bais = new ByteArrayInputStream(srcdata,offset, length);
GZIPInputStream gzis = new GZIPInputStream(bais);
byte[] buf = new byte[1024];
int len = 0;
while ((len = gzis.read(buf)) != -1) {
baos.write(buf, 0, len);
}
gzis.close();
return baos.toByteArray();
}
catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 合成所有FrameUnit中的rawData,形成byte[]
*/
public byte[] mergeImage(Map<Integer,FrameUnit> units){
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
for(int i = 0 ; i < units.size() ; i ++){
FrameUnit u = units.get(i);
baos.write(u.getRawData());
}
return baos.toByteArray() ;
}
catch (Exception e) {
e.printStackTrace();
}
return null ;
}
}
package com.it18zhang.udp.screenbroadcast;
import java.awt.p_w_picpath.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class ClientUI extends JFrame{
private JLabel label ;
private ImageIcon icon ;
public ClientUI(){
ini();
}
/**
* 初始化
*/
private void ini() {
this.setBounds(0,0, 1366, 768);
this.setLayout(null);
//label
label = new JLabel();
label.setBounds(0, 0, 1366, 768);
label.setLayout(null);
//
icon = new ImageIcon("d:/Koala.jpg");
label.setIcon(icon);
this.add(label);
this.setVisible(true);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
/**
* 刷新图片
*/
public void refreshImage(byte[] data) {
label.setIcon(new ImageIcon(data));
}
}
package com.it18zhang.udp.screenbroadcast;
import java.io.ByteArrayOutputStream;
import java.util.zip.GZIPOutputStream;
import java.util.zip.ZipOutputStream;
/**
* 数据工具类
*/
public class DataUtil {
/**
* 使用zip算法进行压缩处理
*/
public static byte[] zipCompress(byte[] data) {
try {
//压缩过程
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(baos);
zos.write(data);
zos.close();
return baos.toByteArray();
}
catch (Exception e) {
e.printStackTrace();
}
return null ;
}
/**
* 使用gzip算法进行压缩处理
*/
public static byte[] gzipCompress(byte[] data) {
try {
//压缩过程
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream gzos = new GZIPOutputStream(baos);
gzos.write(data);
return baos.toByteArray();
}
catch (Exception e) {
e.printStackTrace();
}
return null ;
}
/**
* 将long型数据转换成8个字节
*/
public static byte[] long2Bytes(long l) {
byte[] bytes = new byte[8] ;
bytes[0] = (byte)(l >> 56 );
bytes[1] = (byte)(l >> 48 );
bytes[2] = (byte)(l >> 40 );
bytes[3] = (byte)(l >> 32 );
bytes[4] = (byte)(l >> 24 );
bytes[5] = (byte)(l >> 16 );
bytes[6] = (byte)(l >> 8 );
bytes[7] = (byte)(l >> 0 );
return bytes ;
}
/**
* 将long型数据转换成8个字节
*/
public static long bytes2Long(byte[] bytes) {
long l0 = (bytes[0] & 0xffL) << 56 ;
long l1 = (bytes[1] & 0xffL) << 48 ;
long l2 = (bytes[2] & 0xffL) << 40 ;
long l3 = (bytes[3] & 0xffL) << 32 ;
long l4 = (bytes[4] & 0xffL) << 24 ;
long l5 = (bytes[5] & 0xffL) << 16 ;
long l6 = (bytes[6] & 0xffL) << 8 ;
long l7 = (bytes[7] & 0xffL) << 0 ;
return l0 | l1 | l2 | l3 | l4 | l5 | l6 | l7 ;
}
}
package com.it18zhang.udp.screenbroadcast;
import java.net.DatagramPacket;
/**
* 一帧画面的每个单元 PackProtocal
*/
public class FrameUnit {
// 组id,时间戳
private long gid;
// 包数量
private int count;
// 包序号
private int index;
// 原始数据
private byte[] rawData;
// 构造
public FrameUnit(DatagramPacket pack) {
parsePack(pack);
}
/**
* 解析包结构
*/
private void parsePack(DatagramPacket pack) {
//
byte[] buf = pack.getData();
int length = pack.getLength();
// 处理有效数据
byte[] validData = new byte[length];
System.arraycopy(buf, 0, validData, 0, length);
// gid
this.gid = DataUtil.bytes2Long(validData);
this.count = validData[8];
this.index = validData[9];
// 有效数据
rawData = new byte[length - 10];
System.arraycopy(validData, 10, rawData, 0, length - 10);
}
public long getGid() {
return gid;
}
public void setGid(long gid) {
this.gid = gid;
}
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 byte[] getRawData() {
return rawData;
}
public void setRawData(byte[] rawData) {
this.rawData = rawData;
}
}
package com.it18zhang.udp.screenbroadcast;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.p_w_picpath.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;
import javax.p_w_picpathio.ImageIO;
/**
* 服务器发送
*/
public class ScreenBrocastCastServer {
public static void main(String[] args) throws Exception {
//
DatagramSocket sock = new DatagramSocket(8888);
while(true){
//抓图
byte[] raw = captureScreen();
//创建数据包组
List<DatagramPacket> packs = splitPack(raw,InetAddress.getByName("192.168.12.255") ,8889);
for(DatagramPacket p : packs){
sock.send(p);
}
}
}
/**
* 抓屏
*/
public static byte[] captureScreen(){
try {
//创建屏幕的抓图区域
Rectangle rect = new Rectangle(0, 0, 1024, 768);
BufferedImage p_w_picpath = new Robot().createScreenCapture(rect);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(p_w_picpath, "jpg", baos);
byte[] rawData = baos.toByteArray();
return rawData ;
}
catch (Exception e) {
e.printStackTrace();
}
return null ;
}
/**
* 切割原始报文,生成n个pack对象
*/
public static List<DatagramPacket> splitPack(byte[] rawData,InetAddress addr ,int port){
//总长度
int allLen = rawData.length ;
//每个pack的长度
int lenPerPack = 50 * 1024 ;
//pack的个数
int count = 0 ;
if(allLen % lenPerPack == 0 ){
count = allLen / lenPerPack ;
}
else{
count = allLen / lenPerPack + 1;
}
//构造小包集合
//组id
long gid = System.nanoTime();
List<DatagramPacket> packs = new ArrayList<DatagramPacket>();
DatagramPacket pack = null ;
for(int i = 0 ; i < count ; i ++){
//
byte[] newPack = null ;
//是否是最后一个包
if(i != (count - 1)){
//8个字节:时间戳,
//1个字节:包数量 == count
//1个字节:小包的序号==i
newPack = new byte[lenPerPack + 10];
//处理gid
System.arraycopy(DataUtil.long2Bytes(gid), 0, newPack, 0, 8);
//小包数量
newPack[8] = (byte)count ;
//小包序号
newPack[9] = (byte)i ;
//抓图数据
System.arraycopy(rawData, i * lenPerPack, newPack, 10, lenPerPack);
}
//最后一个包
else{
//8个字节:时间戳,
//1个字节:包数量 == count
//1个字节:小包的序号==i
int remain = rawData.length - (count - 1) * lenPerPack ;//剩余长度
newPack = new byte[remain + 10];
//处理gid
System.arraycopy(DataUtil.long2Bytes(gid), 0, newPack, 0, 8);
//小包数量
newPack[8] = (byte)count ;
//小包序号
newPack[9] = (byte)i ;
//抓图数据
System.arraycopy(rawData, i * lenPerPack, newPack, 10, remain);
}
//创建pack
pack = new DatagramPacket(newPack, newPack.length,addr,port);
//添加到集合中
packs.add(pack);
}
return packs ;
}
}
package com.it18zhang.udp.screenbroadcast;
public class StartClient {
public static void main(String[] args) {
ClientUI ui = new ClientUI();
new ClientReceiverThread(ui).start();
}
}
package com.it18zhang.udp;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class Receiver {
public static void main(String[] args) throws Exception {
DatagramSocket sock = new DatagramSocket(8889);
while(true){
byte[] buf = new byte[1024];
DatagramPacket pack = new DatagramPacket(buf, 1024);
sock.receive(pack);
//获取接收到的消息长度
int len = pack.getLength();
System.out.println(new String(buf,0,len));
Thread.sleep(500);
}
}
}
package com.it18zhang.udp;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/**
* UDP发送器
*/
public class Sender {
public static void main(String[] args) throws Exception {
//8888是数据包套接字端口号,使用该端口向外发送
DatagramSocket sock = new DatagramSocket(8888);
int i = 1 ;
while(true){
//构造数据包套接字对象
//创建缓冲区
byte[] buf = null ;//("helloworld - " + i).getBytes();
buf = new byte[1024 * 60];
//构造数据报包
DatagramPacket pack = new DatagramPacket(buf, buf.length);
//构造发送的地址+port,
//192.168.12.255 ->通配地址,该网段内的所有主机。
InetAddress addr = InetAddress.getByName("192.168.12.255");
pack.setAddress(addr);
pack.setPort(8889);
//通过sock方法数据报包
sock.send(pack);
//编号
i ++ ;
}
}
}
package com.it18zhang.udp;
import com.it18zhang.udp.screenbroadcast.ScreenBrocastCastServer;
public class TestApp {
public static void main(String[] args) {
long l = System.currentTimeMillis();
System.out.println(l);
}
}
**********************************************************************************
学习内容:
java 屏广
遇到问题:
理解屏广意义