android开发之局域网内屏幕共享+提取文字03:socket连接

1、问题
局域网内两个手机互相发送和接受图片
2、方法
通过socket连接,注意,socket是TCP协议的,是面向字节流的,所以发送数据要报头和数据的大小,这样接受方就可以很准确的获得图片
3、代码
1、客户端
①截取Activity的屏幕,与01的方法不一样,这个只是为了熟悉socket,所以只用简单的
②连接服务器
③发送数据

public class MainActivity extends AppCompatActivity implements  View.OnClickListener{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        screenshot();
    }
    private void screenshot() {
        new Thread(new Runnable() {
            @Override
            public void run() {

                while (true) {

                    try {
                        Thread.sleep(1000);
                        // 获取屏幕
                        View dView = getWindow().getDecorView();
//        把屏幕存储在Bitmap
                        dView.destroyDrawingCache();
                        dView.setDrawingCacheEnabled(true);
                        dView.buildDrawingCache();
                        Bitmap bmp = dView.getDrawingCache();
                        if (bmp != null) {
                            try {
                                // 获取内置SD卡路径
                                String sdCardPath = Environment.getExternalStorageDirectory().getPath();
                                // 图片文件路径
                                String filePath = sdCardPath + File.separator + "screenshot.png";
                                Log.d("path", filePath);

                                File file = new File(filePath);
                                FileOutputStream os = new FileOutputStream(file);
                                bmp.compress(Bitmap.CompressFormat.PNG, 30, os);
                                Upload upload = new Upload();
                                upload.uploadFile(file);
                                os.flush();
                                os.close();
                                Toast.makeText(MainActivity.this, "wan", Toast.LENGTH_LONG).show();
                            } catch (Exception e) {
                                Toast.makeText(MainActivity.this, "shi1", Toast.LENGTH_LONG).show();
                            }
                        } else {
                            Toast.makeText(MainActivity.this, "shi2", Toast.LENGTH_LONG).show();
                        }
                    } catch (Exception e) {
                    }
                }
            }
        }).start();

    }
}

Upload类

@SuppressLint("NewApi")
public class Upload {
    // 这里的地址为HOME
    private static final String HOME = "192.168.0.102";

    private static final String BUFF = "--";

    Socket socket = null;
    DataOutputStream output = null;
    DataInputStream input = null;

    public void uploadFile(  final  File file) {


        // 如果本系统为4.0以上(Build.VERSION_CODES.ICE_CREAM_SANDWICH为android4.0)
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
            // 详见StrictMode文档
            StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                    .detectDiskReads().detectDiskWrites().detectNetwork()
                    .penaltyLog().build());
            StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
                    .detectLeakedSqlLiteObjects().detectLeakedClosableObjects()
                    .penaltyLog().penaltyDeath().build());
        }

        new Thread(new Runnable() {
            @Override
            public void run() {

                try {
                    // 连接服务器
                    socket = new Socket(HOME, 8888);
                    // 得到输出流
                    output = new DataOutputStream(socket.getOutputStream());
                    // 得到如入流
                    input = new DataInputStream(socket.getInputStream());

                    /* 取得文件的FileInputStream */
                    FileInputStream fStream = new FileInputStream(file);

                    String[] fileEnd = file.getName().split("\\.");
                    output.writeUTF(BUFF + fileEnd[fileEnd.length - 1].toString());
                    Log.d("path","buffer------------------" + BUFF
                            + fileEnd[fileEnd.length - 1].toString());

                    //设置每次写入102400bytes
                    int bufferSize = 302400;
                    byte[] buffer = new byte[bufferSize];
                    int length = 0;
                    // 从文件读取数据至缓冲区(值为-1说明已经读完)
                    while ((length = fStream.read(buffer)) != -1) {
                        /* 将资料写入DataOutputStream中 */
                        output.write(buffer, 0, length);
                    }
                    // 一定要加上这句,否则收不到来自服务器端的消息返回
                    socket.shutdownOutput();

                    /* close streams */
                    fStream.close();
                    output.flush();

                    /* 取得input内容 */
                    String msg = input.readUTF();
                    Log.d("path","上传成功  文件位置为:" + msg);

                } catch (UnknownHostException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            }
        }).start();
    }
}

2、服务器
①监听端口
②连接服务器
③接受数据
④显示在ImageView

public class MainActivity extends AppCompatActivity {



    // ServerSocket的引用
    ServerSocket ss = null;
    // socket的引用
    Socket socket = null;
    DataInputStream input = null;
    DataOutputStream output = null;
//    报头,验证用
    public final static byte[] PICTURE_PACKAGE_HEAD = {(byte) 0xFF, (byte) 0xCF,
            (byte) 0xFA, (byte) 0xBF, (byte) 0xF6, (byte) 0xAF, (byte) 0xFE,
            (byte) 0xFF};

    // socket端口
    private final static int PORT = 8888;

    static ImageView imageView;

//由于更新UI一定要这样弄子线程,由于UI消耗太大
    private static Handler handler = new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            Bitmap bitmap = BitmapFactory.decodeByteArray((byte[]) msg.obj, 0,msg.what );
            imageView.setImageBitmap(bitmap);
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        imageView=findViewById(R.id.image);
        new Thread(new Runnable() {
            @Override
            public void run() {

//                服务器监听功能是一直存在的
                try {
                    // 监听到8888端口
                    ss = new ServerSocket(PORT);
                    Log.d("path","已监听到" + PORT + "端口");
                    Log.d("path",new Date().toString() + " \n 服务器已经启动...");
//                    判断是否连接了客户端
                    while(socket == null || socket.isClosed())
                        socket = ss.accept();
                    Log.d("path",new Date().toString() + " \n 已经连接客户端...");
                    // 得到输入流
                    input = new DataInputStream(socket.getInputStream());
                    // 得到输出流
                    output = new DataOutputStream(socket.getOutputStream());
                  // 更新UI
                    SocketUpLoad(input);
                } catch (IOException e) {
                    Log.d("path","连接客户端失败")  ;
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }).start();
    }


    /**
     * 上传
     *
     * @param input
     */
    private void  SocketUpLoad(final DataInputStream input) {
new Thread(new Runnable() {
    @Override
    public void run() {
        while(true)
            try {
             Thread.sleep(3000);
//                DataInputStream inputStream = input;

                //标志头状态
                boolean isHead = true;
                //循环读取PICTURE_PACKAGE_HEAD.length个字节,并判断是否和我们定义的头相同
                for (int i = 0; i < PICTURE_PACKAGE_HEAD.length; ++i) {
//                    Log.d("path","成功1")  ;
                    byte head = (byte) input.read();
//                    Log.d("path","成功2")  ;
                    //如果不相同,那么结束循环,并丢弃这个字节
                    if (head != PICTURE_PACKAGE_HEAD[i]) {
                        isHead = false;
                        Log.d("path","失败,报头不一样")  ;
                        break;
                    }
                }
//                Log.d("path","获得报头")  ;
                if(isHead){

                        long picLeng = input.readLong();
                        //new 一个字节数据输出流
                        ByteArrayOutputStream fos = new ByteArrayOutputStream();
                        //每一次读CACHE_SIZE个字节,
                        byte[] buffer = new byte[102400];
                        int len = -1;
                        //循环读取
                        while (picLeng > 0 && (len = input.read(buffer, 0, picLeng < buffer.length ? (int) picLeng : buffer.length)) != -1) {
                            fos.write(buffer, 0, len);
                            fos.flush();
                            //每读取后,picLeng的值要减去len个,直到picLeng = 0
                            picLeng -= len;
                        }
                        fos.flush();
                        buffer = null;

                        // 如果发现picLeng 不为0,说明图片接收不完整,那么就放弃这段数据
                        if (picLeng > 0) {
                            continue;
                        }
                        //如果以上操作都成功,那么就取出图片数据
                        byte[] pictures = fos.toByteArray();
                        //然后使用相应的工具类就可以把pictures转化为图片了
                        fos.close();
                        fos = null;
                        Message message = new Message();
                        message.obj = pictures;
                        message.what = pictures.length;
                        handler.sendMessage(message);
                    Log.d("path","获得图片数据")  ;
                   }
                }catch (Exception e){
                Log.d("path","run中失误")  ;
            }
            }
}).start();


    }

四、
先去看看socket工作原理
五、
完成版:源码
参考资料
android选择图片并使用socket上传图片
Java Socket连续传输多张图片(不断开链接)

你可能感兴趣的:(Android,android)