通过socket传送图片的问题

paperen 2012-04-23 08:28:21
通过socket传送客户端屏幕图片,但接收端好像始终有数据接收,而接收的数据量会大于送出的图片大小,比较原图片与收到的文件十六进制数据完全不同,本人小白,请各位给我点指导,谢

部分代码如下:

客户端

public class Client
{

public static void main( String[] args )
{

try
{
Socket client = new Socket( "localhost", 5888 );

OutputStream sender = client.getOutputStream();

// 获取到屏幕图片数据
BufferedImage img = Screen.SnapShot();
// 生成文件 这里是可以生成图片的,大小大概为88.7kb
ImageIO.write(img, "png", new File("screen.png"));

// 转为比特后发送
sender.write( Client.getCompressedImage( img ) );

client.close();
}
catch ( IOException e )
{
e.printStackTrace();
}

}

/**
* 图片转换为byte
* @param image
* @return
*/
public static byte[] getCompressedImage( BufferedImage image )
{
byte[] imageData = null;

try
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write( image, "png", baos );
imageData = baos.toByteArray();
}
catch ( IOException ex )
{
imageData = null;
}

return imageData;
}
}


服务端

public class Server
{

/**
* @param args the command line arguments
*/
public static void main( String[] args )
{
try
{
ServerSocket server = new ServerSocket( 5888 );
Socket client = server.accept();

InputStream inputStream = client.getInputStream();
Scanner sc = new Scanner( inputStream );

String result = "";
int counter = 0;
while( sc.hasNextLine() )
{
result += sc.nextLine();
// 直接限制到400行就停止了,不加的话会一直循环…
if ( counter++ == 400 ) break;
}
byte[] resultToBytes = result.getBytes();

FileOutputStream out = new FileOutputStream( "test.png" );
// 生成的文件大于88.7kb 而且16进制与原图片的不同
out.write( resultToBytes );
out.close();

client.close();
}
catch ( IOException e )
{
e.printStackTrace();
}
}
}
...全文
796 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
MiceRice 2012-04-26
  • 打赏
  • 举报
回复
客观地说,不太容易了,毕竟Java的能力就摆在那里,有几种建议:
1、如果你用的是JNI来截屏的话,考虑截屏时就完成压缩;另外截屏时,可以考虑降低色彩数,用16位色(65536)即可;
2、使用JNI调用DirectX的库来对图片进行压缩;这个确实比较麻烦的;
3、启用另一线程执行压缩,不过这个也只能节约掉“截取图片 15 毫秒”;
4、不压缩或使用压缩比更小速度更快的算法,如果你是在内网的话。
paperen 2012-04-26
  • 打赏
  • 举报
回复
结贴了,还是感谢mice,如日后有收获会继续补贴
paperen 2012-04-26
  • 打赏
  • 举报
回复
[Quote=引用 20 楼 的回复:]

我想了下,现在新电脑CPU都是双核,再开超线程的话。相当于差不多可以并行4个线程。

考虑改成多线程处理吧可以提升响应速度的。

比如两条线程A和B,那么:
A做压缩的时候,B就去截图;
A压缩完毕后,B基本截图完毕;
A去发送数据,B开始压缩;
A接着去截图,B继续压缩;

B压缩完毕后,A基本截图完毕;
B去发送数据,A开始压缩;
B接着去截图,A继续压缩;

A……
[/Quote]

好像行得通!我try try看
MiceRice 2012-04-26
  • 打赏
  • 举报
回复
我想了下,现在新电脑CPU都是双核,再开超线程的话。相当于差不多可以并行4个线程。

考虑改成多线程处理吧可以提升响应速度的。

比如两条线程A和B,那么:
A做压缩的时候,B就去截图;
A压缩完毕后,B基本截图完毕;
A去发送数据,B开始压缩;
A接着去截图,B继续压缩;

B压缩完毕后,A基本截图完毕;
B去发送数据,A开始压缩;
B接着去截图,A继续压缩;

A压缩完毕后,B基本截图完毕;
A去发送数据,B开始压缩;
A接着去截图,B继续压缩;

......

可以看到,在双核下的话,你的每次迭代周期都是 35毫秒,截图和发送的15毫秒,可以在迭代中同步完成。

当然你也可以用3线程甚至4线程,从而企图让刷新周期进一步压缩,但如果不是多核CPU或多线程的话,就没有实际效果了。
paperen 2012-04-26
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 的回复:]

刚才看了下,有个压缩速度更快的,消耗时间大概是ImageIO的40%,不过是由sun提供的私有包(JDK自带了):

Java code

import com.sun.image.codec.jpeg.*;

public static byte[] getCompressedImageAWT(BufferedImage image) {
byte[] image……
[/Quote]
谢谢啊!还刚想结贴来着,1024*250画面的话 果然快了~平均下来压缩那里用了三十多毫秒吧

图片总大小 92039
打包与发送总用时 0 毫秒
截取图片 15 毫秒
压缩用时 35 毫秒

随着画面尺寸增大还是有很大影响,不过这个确实是必然的,我转转思路再试试
paperen 2012-04-26
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 的回复:]

客观地说,不太容易了,毕竟Java的能力就摆在那里,有几种建议:
1、如果你用的是JNI来截屏的话,考虑截屏时就完成压缩;另外截屏时,可以考虑降低色彩数,用16位色(65536)即可;
2、使用JNI调用DirectX的库来对图片进行压缩;这个确实比较麻烦的;
3、启用另一线程执行压缩,不过这个也只能节约掉“截取图片 15 毫秒”;
4、不压缩或使用压缩比更小速度更快的算法,如果你是在内……
[/Quote]
很感谢mice,那我得去看看DirectX,似乎在java上再去优化有麻烦了,找了点DirectX的例子看都是C++的。自己学的还是不够多,要求延迟少的话截图的办法貌似有点难度,好吧,此贴到此为止吧,我最后将目前的代码全贴上,不是什么好代码,但是也算一个总结吧

服务端

package server;

import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.*;
import java.net.Socket;
import java.util.Scanner;
import java.util.Timer;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Server
{
/**
* @param args the command line arguments
*/
public static void main( String[] args ) throws InterruptedException
{
ImageFrame frame = new ImageFrame();
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.setVisible( true );

// 无限制
boolean noLimit = true;
int totalImgNum = 6;
try
{
ServerSocket server = new ServerSocket( 5888 );
Socket client = server.accept();

InputStream inputStream = client.getInputStream();

int counter = 0;
long timeCounter = 0;
int imageCounter = 0;
while ( true )
{
if ( counter == totalImgNum && !noLimit )
{
System.out.println( "stop" );
break;
}

// 接收开始符
byte[] newTagByte = new byte[5];
inputStream.read( newTagByte );
String tag = new String( newTagByte, 0, newTagByte.length );
System.out.println( "图片开始接收" );
while ( tag.equals( "start" ) )
{
// 开始接收时间
long startMillis = System.currentTimeMillis();
System.out.println( "开始接收" );

++counter;

// 图片数据总大小
int imgSize;
byte[] imgSizeBytes = new byte[4];
inputStream.read( imgSizeBytes );
imgSize = Server.bytesToInt( imgSizeBytes );

// 总包数
byte[] packageBytes = new byte[4];
inputStream.read( packageBytes );
// 竟然会有25的
int packageNum = Server.bytesToInt( packageBytes );
//System.out.println( packageNum );

// 每包每包地读取数据
// 为数据开辟全部空间
byte[] result = new byte[imgSize];
// 总读取的字节数
int readByte = 0;
for ( int i = 1; i <= packageNum; i++ )
{
long packageStartMillis = System.currentTimeMillis();
// 获取每包的大小
byte[] packageSizeByte = new byte[4];
inputStream.read( packageSizeByte );
int packageSize = Server.bytesToInt( packageSizeByte );
//System.out.println( packageSize );
Thread.sleep( 25 );

// 开辟包 有时候会出现负值
byte[] tmp = new byte[packageSize];
inputStream.read( tmp );

// 装载到result中
System.arraycopy( tmp, 0, result, readByte, packageSize );
readByte += packageSize;

long packageEndMillis = System.currentTimeMillis();
System.out.println( "第" + i + "个包接收使用了 " + ( packageEndMillis - packageStartMillis ) + "毫秒" );
}

long endMillis = System.currentTimeMillis();
System.out.println( "总数据大小 " + result.length );
System.out.println( "接收完毕 用了" + ( endMillis - startMillis ) + "毫秒" );
timeCounter += ( endMillis - startMillis );

// 接收结束符
byte[] endTagByte = new byte[3];
inputStream.read( endTagByte );
tag = new String( endTagByte, 0, endTagByte.length );
imageCounter++;
System.out.println( "图片接收完毕" );

// 如果超过1秒
if ( timeCounter >= 1000 )
{
System.out.println( "1秒内接收了 " + imageCounter + " 张图片" );
imageCounter = 0;
timeCounter = 0;
}

// 显示
image = Toolkit.getDefaultToolkit().createImage( result, 0, result.length );
frame.updateImage();
}
}

client.close();
}
catch ( IOException e )
{
e.printStackTrace();
}
}

public static int bytesToInt( byte[] bytes )
{
int num = bytes[0] & 0xFF;
num |= ((bytes[1] << 8) & 0xFF00);
num |= ((bytes[2] << 16) & 0xFF0000);
num |= ((bytes[3] << 24) & 0xFF000000);
return num;
}
public static Image image;
}

class ImageFrame extends JFrame
{

private ImagePanel _panel;
static final int DEFAULT_WIDTH = 1024;
static final int DEFAULT_HEIGHT = 768;

public ImageFrame()
{
this.setTitle( "test" );
this.setSize( DEFAULT_WIDTH, DEFAULT_HEIGHT );

_panel = new ImagePanel();
this.add( _panel );
}

public void updateImage() throws InterruptedException
{
_panel.refresh();
_panel.repaint();
}
}

class ImagePanel extends JPanel
{

private Image image;

public ImagePanel()
{
this.setDoubleBuffered( true );
image = Server.image;
}

public void refresh()
{
image = Server.image;
}

public void paintComponent( Graphics g )
{
//super.paintComponent( g );
g.drawImage( image, 0, 0, this );
}
}


客户端

package client;

import java.awt.Robot;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import javax.imageio.*;
import java.net.*;
import java.net.Socket;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.WritableRaster;

public class Client
{

public static void main( String[] args ) throws InterruptedException
{
// 无限制
boolean noLimit = true;
int totalImgNum = 80;
try
{
Socket client = new Socket( "200.200.200.117", 5888 );// 请根据自己实际更改IP

OutputStream sender = client.getOutputStream();

int counter = 0;
while ( true )
{
if ( counter++ == totalImgNum && !noLimit )
{
break;
}

long compressedStartTime = System.currentTimeMillis();
// 获取到屏幕图片数据
BufferedImage img = Screen.SnapShot();
System.out.println( "截取图片 " + (System.currentTimeMillis() - compressedStartTime) + " 毫秒" );

// 压缩图片数据
compressedStartTime = System.currentTimeMillis();
byte[] imgToBytes = Client.getCompressedImage( img );
System.out.println( "压缩用时 " + (System.currentTimeMillis() - compressedStartTime) + " 毫秒" );

// 发送开始符
sender.write( "start".getBytes() );

// 发送总大小
int imgSize = imgToBytes.length;
System.out.println( "图片总大小 " + imgSize );
sender.write( Client.intToByte( imgSize ) );

// 拆包发送
// 打包开始时间
long unpackageStartMillis = System.currentTimeMillis();

// 每段字节数
int packageSize = 51200;
// 总包数
int packageNum = (imgSize % packageSize != 0) ? imgSize / packageSize + 1 : imgSize / packageSize;
// 发送总包数
sender.write( Client.intToByte( packageNum ) );

int pos = 0;
for ( int i = 1; i <= packageNum; i++ )
{
// 每包大小
int tmpSize = (i * packageSize > imgSize) ? imgSize - (i - 1) * packageSize : packageSize;

// 发送每包的大小
sender.write( Client.intToByte( tmpSize ) );

// 装载数据并发送
byte[] tmp = new byte[tmpSize];
System.arraycopy( imgToBytes, pos, tmp, 0, tmpSize );
pos += tmpSize;
sender.write( tmp );
}

// 打包与发送完毕时间
long unpackageEndMillis = System.currentTimeMillis();
System.out.println( "打包与发送总用时 " + (unpackageEndMillis - unpackageStartMillis) + " 毫秒" );

// 发送结束符
sender.write( "end".getBytes() );
}

client.close();
}
catch ( IOException e )
{
e.printStackTrace();
}

}

public static byte[] intToByte( int i )
{
byte[] bt = new byte[4];
bt[0] = (byte) (0xff & i);
bt[1] = (byte) ((0xff00 & i) >> 8);
bt[2] = (byte) ((0xff0000 & i) >> 16);
bt[3] = (byte) ((0xff000000 & i) >> 24);
return bt;
}

/**
* 图片转换为byte
* @param image
* @return
*/
public static byte[] getCompressedImage( BufferedImage image )
{
byte[] imageData = null;

try
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write( image, "png", baos );
imageData = baos.toByteArray();
}
catch ( IOException ex )
{
imageData = null;
}

return imageData;
}

public static byte[] imageByteData( BufferedImage image )
{
WritableRaster raster = image.getRaster();
DataBufferByte buffer = (DataBufferByte) raster.getDataBuffer();
return buffer.getData();
}
}

class Screen
{
final static int WIDTH = 1024;
final static int HEIGHT = 250;

/**
* 屏幕抓取
*/
public static BufferedImage SnapShot()
{
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
screenSize.setSize( WIDTH, HEIGHT );
Rectangle screenRectangle = new Rectangle( screenSize );
try
{
Robot robot = new Robot();
BufferedImage image = robot.createScreenCapture( screenRectangle );
return image;
}
catch ( AWTException e )
{
e.printStackTrace();
return null;
}
}
}


还是谢谢mice
MiceRice 2012-04-26
  • 打赏
  • 举报
回复
刚才看了下,有个压缩速度更快的,消耗时间大概是ImageIO的40%,不过是由sun提供的私有包(JDK自带了):


import com.sun.image.codec.jpeg.*;

public static byte[] getCompressedImageAWT(BufferedImage image) {
byte[] imageData = null;
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(baos);
encoder.encode(image);
imageData = baos.toByteArray();
} catch (IOException ex) {
ex.printStackTrace();
}
return imageData;
}


默认情况下会编译不通过:
Access restriction: The type JPEGImageEncoder is not accessible due to restriction on required library

需要修改:
Eclipse 默认把这些受访问限制的API设成了ERROR。只要把Windows->Preferences->Java->Complicer-> Errors/Warnings里面的Deprecated and restricted API中的Forbidden references(access rules)选为Warning就可以编译通过。
ZLNFSM919929 2012-04-25
  • 打赏
  • 举报
回复
楼主能问题下您现在做的是什么东西吗?能讨论一下吗?我现在做的系统也有图片文件的发送。。。。。。。。。。。。。。。。
paperen 2012-04-25
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 的回复:]

引用 13 楼 的回复:
我将super.paintComponent( g );注释掉就不会闪烁了,我还不了解原理


其实也想跟你说去掉super的调用,因为super会先清屏,然后再进行重绘。

而你这里实际上每次都是完整显示全图,所以根本不需要清屏。

以上。。。
[/Quote]

mice!现在就差延迟问题了!我确定问题所在了,在压缩那里,如果能将压缩的用时再降低到50毫秒就可以很流畅了,有没有不经过ImageIO去从BufferedImage获取byte的办法或资料能给我参考?

// 这是我调试客户端输出每部分占用的时间
图片总大小 37361
打包与发送总用时 0 毫秒
截取图片 15 毫秒
压缩用时 172 毫秒

// 压缩部分
/**
* 图片转换为byte
* @param image
* @return
*/
public static byte[] getCompressedImage( BufferedImage image )
{
byte[] imageData = null;

try
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write( image, "jpg", baos );
imageData = baos.toByteArray();
}
catch ( IOException ex )
{
imageData = null;
}

return imageData;
}


让我惊奇的是打包与发送那里竟然是0毫秒
MiceRice 2012-04-25
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 的回复:]
我将super.paintComponent( g );注释掉就不会闪烁了,我还不了解原理
[/Quote]

其实也想跟你说去掉super的调用,因为super会先清屏,然后再进行重绘。

而你这里实际上每次都是完整显示全图,所以根本不需要清屏。

以上。。。
paperen 2012-04-25
  • 打赏
  • 举报
回复
我将super.paintComponent( g );注释掉就不会闪烁了,我还不了解原理
paperen 2012-04-25
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 的回复:]

楼主能问题下您现在做的是什么东西吗?能讨论一下吗?我现在做的系统也有图片文件的发送。。。。。。。。。。。。。。。。
[/Quote]

做着玩而已,练手
paperen 2012-04-25
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 的回复:]

随着屏幕比例的大小延迟更明显
——正常,屏幕越大,压缩数据量越多,耗费内存越高
——比较值得改进的问题是,你的Client端程序做了两次:png压缩,而png压缩是压缩率较低且开销较高的压缩算法;
——建议先得到byte[] imgToBytes = Client.getCompressedImage( img );然后直接把这个字节数组写入文件就好了。


不时会出现一些异常情况,……
[/Quote]

Mice 我调整了服务端接收的数据不写入tmp文件了也不使用png了,响应速度快了很多,但是updateUI出现闪烁,查了一些关于双缓存的资料但没有头绪,试过手动设置this.setDoubleBuffered( true );也没用,是不是我的main使用了while的原因
paperen 2012-04-24
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 的回复:]

随着屏幕比例的大小延迟更明显
——正常,屏幕越大,压缩数据量越多,耗费内存越高
——比较值得改进的问题是,你的Client端程序做了两次:png压缩,而png压缩是压缩率较低且开销较高的压缩算法;
——建议先得到byte[] imgToBytes = Client.getCompressedImage( img );然后直接把这个字节数组写入文件就好了。


不时会出现一些异常情况,……
[/Quote]

非常感谢你的回复!是啊,客户端生成了文件然后读取再送是会减慢了速度,确实没想到png那里也会消耗太多,我再根据你说的与自己的思路再加以优化一下看看,再谢一个
MiceRice 2012-04-24
  • 打赏
  • 举报
回复
随着屏幕比例的大小延迟更明显
——正常,屏幕越大,压缩数据量越多,耗费内存越高
——比较值得改进的问题是,你的Client端程序做了两次:png压缩,而png压缩是压缩率较低且开销较高的压缩算法;
——建议先得到byte[] imgToBytes = Client.getCompressedImage( img );然后直接把这个字节数组写入文件就好了。


不时会出现一些异常情况,比如包的数量莫名奇妙的变大为25,包大小变了负值
——没有认真调试你的程序,不好说
——但我认为没必要拆包,直接整个byte数组扔给 OutputStream sender 就好了,拆包增加复杂度,浪费内存,浪费copy时间,而且关键是没看到带来了啥好处


不知道将byte[]转为int那个方法是否有错?
——除了最后那个以外,没啥问题:
byte[] targets = new byte[4];
targets[0] = (byte) (res & 0xff);// 最低位
targets[1] = (byte) ((res >> 8) & 0xff);// 次低位
targets[2] = (byte) ((res >> 16) & 0xff);// 次高位
targets[3] = (byte) (res >>> 24);// 最高位,无符号右移。
——但逻辑上来说,你原始值只要不是负数就应该不存在符号位问题


还有程序占用了较多的内存
——很正常,自己算算就知道了:
1024宽×768高×32位色彩 = 3MB
1920宽×768高×32位色彩 = 8.16MB
这都是实打实的内存开销。
paperen 2012-04-24
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 的回复:]

Java code
private Scanner(Readable source, Pattern pattern) {
assert source != null : "source should not be null";
assert pattern != null : "pattern should not be null";
……
[/Quote]

sorry,我没看明白什么意思…但也谢谢
paperen 2012-04-24
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 的回复:]

c/s结构没玩过,帮顶!
[/Quote]

thx!
paperen 2012-04-24
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 的回复:]

读取二进制流,请不要用Scanner,这个是用来处理文本流的,也就是必须是可识别字符才能正确处理。
[/Quote]

现在很傻瓜地能实现了功能(我不知道这样实现是否合理)但是这种传送方式我自己看起来都觉得有点白痴,是否应该使用线程传输?而且这样接收包数据会有错误,而我目前又有了新问题:

随着屏幕比例的大小延迟更明显
不时会出现一些异常情况,比如包的数量莫名奇妙的变大为25,包大小变了负值,不知道将byte[]转为int那个方法是否有错?
还有程序占用了较多的内存

这些虽然不与这个问题有关,但希望能再给我点提示,谢谢

目前的部分代码

服务端

public class Server
{

/**
* @param args the command line arguments
*/
public static void main( String[] args ) throws InterruptedException
{
ImageFrame frame = new ImageFrame();
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.setVisible( true );

// 无限制
boolean noLimit = true;
int totalImgNum = 80;
try
{
ServerSocket server = new ServerSocket( 5888 );
//server.bind( new InetSocketAddress( "200.200.200.117", 5888 ) );
Socket client = server.accept();

InputStream inputStream = client.getInputStream();

int counter = 0;

while ( true )
{
if ( counter == totalImgNum && !noLimit )
{
System.out.println( "stop" );
break;
}

// 接收开始符
byte[] newTagByte = new byte[5];
inputStream.read( newTagByte );
String tag = new String( newTagByte, 0, newTagByte.length );
System.out.println( tag );
while ( tag.equals( "start" ) )
{
++counter;

// 图片数据总大小
int imgSize;
byte[] imgSizeBytes = new byte[4];
inputStream.read( imgSizeBytes );
imgSize = Server.bytesToInt( imgSizeBytes );
System.out.println( imgSize );

// 总包数
byte[] packageBytes = new byte[4];
inputStream.read( packageBytes );
// 竟然会有25的
int packageNum = Server.bytesToInt( packageBytes );
System.out.println( packageNum );

// 每包每包地读取数据
// 为数据开辟全部空间
byte[] result = new byte[imgSize];
// 总读取的字节数
int readByte = 0;
for ( int i = 1; i <= packageNum; i++ )
{
// 获取每包的大小
byte[] packageSizeByte = new byte[4];
inputStream.read( packageSizeByte );
int packageSize = Server.bytesToInt( packageSizeByte );
System.out.println( packageSize );
Thread.sleep( 90 );

// 开辟包 有时候会出现负值
byte[] tmp = new byte[packageSize];
inputStream.read( tmp );

// 装载到result中
System.arraycopy( tmp, 0, result, readByte, packageSize );
readByte += packageSize;
}
System.out.println( result.length );


// 生成文件
String imgName = "test";
File img = new File( imgName );
img.createNewFile();
// 写入文件
FileOutputStream out = new FileOutputStream( imgName );
out.write( result );
out.close();

// 显示
image = ImageIO.read( img );
frame.updateImage();

// 删除图片
img.delete();

// 接收结束符
byte[] endTagByte = new byte[3];
inputStream.read( endTagByte );
tag = new String( endTagByte, 0, endTagByte.length );
System.out.println( tag );
}
}

client.close();
}
catch ( IOException e )
{
e.printStackTrace();
}
}

public static int bytesToInt( byte[] bytes )
{
int num = bytes[0] & 0xFF;
num |= ((bytes[1] << 8) & 0xFF00);
num |= ((bytes[2] << 16) & 0xFF0000);
num |= ((bytes[3] << 24) & 0xFF000000);
return num;
}
public static Image image;
}

class ImageFrame extends JFrame
{

private ImagePanel _panel;
static final int DEFAULT_WIDTH = 1024;
static final int DEFAULT_HEIGHT = 768;

public ImageFrame()
{
setTitle( "test" );
setSize( DEFAULT_WIDTH, DEFAULT_HEIGHT );

_panel = new ImagePanel();
add( _panel );
}

public void updateImage()
{
_panel.refresh();
_panel.updateUI();
}
}

class ImagePanel extends JPanel
{

private Image image;

public ImagePanel()
{
image = Server.image;
}

public void refresh()
{
image = Server.image;
}

public void paintComponent( Graphics g )
{
super.paintComponent( g );
g.drawImage( image, 0, 0, this );
}
}


客户端

public class Client
{

public static void main( String[] args ) throws InterruptedException
{
// 无限制
boolean noLimit = true;
int totalImgNum = 80;
try
{
Socket client = new Socket( "200.200.200.117", 5888 );

OutputStream sender = client.getOutputStream();

int counter = 0;
while ( true )
{
if ( counter++ == totalImgNum && !noLimit )
{
break;
}

// 发送开始符
sender.write( "start".getBytes() );
//Thread.sleep( 5 );

// 获取到屏幕图片数据
BufferedImage img = Screen.SnapShot();

// 生成文件 这里是可以生成图片的,大小大概为88.7kb
File imgFile = new File( "screen.png" );
imgFile.createNewFile();
ImageIO.write( img, "png", imgFile );
byte[] imgToBytes = Client.getCompressedImage( img );

// 发送总大小
int imgSize = imgToBytes.length;
System.out.println( imgSize );
sender.write( Client.intToByte( imgSize ) );
//Thread.sleep( 10 );

// 拆包发送

// 每段字节数
int packageSize = 51200;
// 总包数
int packageNum = (imgSize % packageSize != 0) ? imgSize / packageSize + 1 : imgSize / packageSize;
// 发送总包数
sender.write( Client.intToByte( packageNum ) );
//Thread.sleep( 10 );

int pos = 0;
for ( int i = 1; i <= packageNum; i++ )
{
// 每包大小
int tmpSize = (i * packageSize > imgSize) ? imgSize - (i - 1) * packageSize : packageSize;

// 发送每包的大小
sender.write( Client.intToByte( tmpSize ) );
//Thread.sleep( 10 );

// 装载数据并发送
byte[] tmp = new byte[tmpSize];
System.arraycopy( imgToBytes, pos, tmp, 0, tmpSize );
pos += tmpSize;
sender.write( tmp );
//Thread.sleep( 10 );
}

// 发送结束符
//Thread.sleep( 30 );
sender.write( "end".getBytes() );
}

client.close();
}
catch ( IOException e )
{
e.printStackTrace();
}

}

public static byte[] intToByte( int i )
{
byte[] bt = new byte[4];
bt[0] = (byte) (0xff & i);
bt[1] = (byte) ((0xff00 & i) >> 8);
bt[2] = (byte) ((0xff0000 & i) >> 16);
bt[3] = (byte) ((0xff000000 & i) >> 24);
return bt;
}

/**
* 图片转换为byte
* @param image
* @return
*/
public static byte[] getCompressedImage( BufferedImage image )
{
byte[] imageData = null;

try
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write( image, "png", baos );
imageData = baos.toByteArray();
}
catch ( IOException ex )
{
imageData = null;
}

return imageData;
}
}
CoffeePhoton 2012-04-23
  • 打赏
  • 举报
回复
c/s结构没玩过,帮顶!
  • 打赏
  • 举报
回复
    private Scanner(Readable source, Pattern pattern) {
assert source != null : "source should not be null";
assert pattern != null : "pattern should not be null";
this.source = source;
delimPattern = pattern;
buf = CharBuffer.allocate(BUFFER_SIZE);
buf.limit(0);
matcher = delimPattern.matcher(buf);
matcher.useTransparentBounds(true);
matcher.useAnchoringBounds(false);
useLocale(Locale.getDefault(Locale.Category.FORMAT));
}
加载更多回复(2)

62,612

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧