通过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();
}
}
}

解决方案 »

  1.   

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

  2.   

        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));
        }
      

  3.   


    现在很傻瓜地能实现了功能(我不知道这样实现是否合理)但是这种传送方式我自己看起来都觉得有点白痴,是否应该使用线程传输?而且这样接收包数据会有错误,而我目前又有了新问题:随着屏幕比例的大小延迟更明显
    不时会出现一些异常情况,比如包的数量莫名奇妙的变大为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;
    }
    }
      

  4.   


    sorry,我没看明白什么意思…但也谢谢
      

  5.   

    随着屏幕比例的大小延迟更明显
    ——正常,屏幕越大,压缩数据量越多,耗费内存越高
    ——比较值得改进的问题是,你的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
    这都是实打实的内存开销。
      

  6.   


    非常感谢你的回复!是啊,客户端生成了文件然后读取再送是会减慢了速度,确实没想到png那里也会消耗太多,我再根据你说的与自己的思路再加以优化一下看看,再谢一个
      

  7.   


    Mice 我调整了服务端接收的数据不写入tmp文件了也不使用png了,响应速度快了很多,但是updateUI出现闪烁,查了一些关于双缓存的资料但没有头绪,试过手动设置this.setDoubleBuffered( true );也没用,是不是我的main使用了while的原因
      

  8.   

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

  9.   


    其实也想跟你说去掉super的调用,因为super会先清屏,然后再进行重绘。而你这里实际上每次都是完整显示全图,所以根本不需要清屏。以上
      

  10.   


    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毫秒
      

  11.   

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

  12.   

    刚才看了下,有个压缩速度更快的,消耗时间大概是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就可以编译通过。
      

  13.   

    很感谢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
      

  14.   

    我想了下,现在新电脑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或多线程的话,就没有实际效果了。
      

  15.   


    好像行得通!我try try看
      

  16.   

    结贴了,还是感谢mice,如日后有收获会继续补贴