首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > JAVA > J2SE开发 >

通过socket传送图片的有关问题

2012-05-03 
通过socket传送图片的问题通过socket传送客户端屏幕图片,但接收端好像始终有数据接收,而接收的数据量会大

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

部分代码如下:

客户端

Java code
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;    }}


服务端
Java code
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();        }    }}


[解决办法]
读取二进制流,请不要用Scanner,这个是用来处理文本流的,也就是必须是可识别字符才能正确处理。
[解决办法]
Java code
    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);        [color=#FF0000]useLocale(Locale.getDefault(Locale.Category.FORMAT));[/color]    }
[解决办法]
c/s结构没玩过,帮顶!
[解决办法]
随着屏幕比例的大小延迟更明显
——正常,屏幕越大,压缩数据量越多,耗费内存越高
——比较值得改进的问题是,你的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
这都是实打实的内存开销。
[解决办法]

探讨
我将super.paintComponent( g );注释掉就不会闪烁了,我还不了解原理

[解决办法]
客观地说,不太容易了,毕竟Java的能力就摆在那里,有几种建议:
1、如果你用的是JNI来截屏的话,考虑截屏时就完成压缩;另外截屏时,可以考虑降低色彩数,用16位色(65536)即可;
2、使用JNI调用DirectX的库来对图片进行压缩;这个确实比较麻烦的;
3、启用另一线程执行压缩,不过这个也只能节约掉“截取图片 15 毫秒”;
4、不压缩或使用压缩比更小速度更快的算法,如果你是在内网的话。

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

Java code
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;    } 

热点排行