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連續傳輸多張圖片(不斷開鏈接)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章