2018년 4월 15일 일요일

usb connection to pc in Android(2)


https://swlock.blogspot.com/2018/04/usb-connection-to-pc-in-android.html

지난 글에 이어서 이번에는 해당 소스 분석입니다.


APK 측

전화기에서 Socket server를 생성합니다.
아래 소스입니다. 30300 은 APK 내에서의 서버 Listen 소켓을 의미합니다.
이때 타임 아웃을 60초로 두었습니다. 필요에 따라 조정 하면 됩니다.

    public static final int TIMEOUT=60;
                    server = new ServerSocket(30300);
                    server.setSoTimeout(TIMEOUT * 1000);

                    Log.d(TAG, "Waiting for connection.");

아래 구문에서 client의 접속이 들어오기 전까지 blocking 됩니다. 그래서 thread로 작성이 되었습니다.

                    //attempt to accept a connection
                    client = server.accept();

이 connection은 한번만 하나의 장치만 연결하는 목적이므로 finally 구문에서 서버 소켓을 close 해줍니다. server.close()

                } finally {
                    //close the server socket
                    try {
                        if (server!=null)
                            Log.d(TAG, "Closing server");
                        server.close();
                    } catch (IOException ec) {
                        Log.e(TAG, "Cannot close server socket" + ec);
                    }
                }

서버에 client 가 연결되자 마자 Globals.connected 가 true가 됩니다.

그리고 시작하자마자 tx thread를 만들어 줍니다.
해당 코드는 Globals.connected true일때만 동작하게 됩니다.
지속적으로 현재시간을 socket에 write를 합니다.

                while(true){
                    while(Globals.connected) {
                        Log.d(TAG, "writing things");
                        Globals.socketOut.write("Time: " + System.currentTimeMillis() + "\n");
                        Globals.socketOut.flush();


UI 메세지 전달은 handler를 통해서 진행합니다. thread안에서 화면에 문구를 업데이트 하는 부분은 어렵기 때문에 handler.post에 showConnectionStatus 를 호출하면 Handler가 this.mHandler = new Handler(); 를 Creat시 생성해두었기 때문에 ui thread에서 실행이 됩니다.

                    connectionStatus="Connection was successful!";
                    mHandler.post(showConnectionStatus);

=> 아래 코드가 실행 됩니다.
    private Runnable showConnectionStatus = new Runnable() {
        public void run() {
            Toast.makeText(MainActivity.this, connectionStatus, Toast.LENGTH_SHORT).show();
        }
    };


ADB에 의해서 port forward로 PC 10300 포트가 단말 30300 번 과 연결이 되어 있습니다.
따라서 10300으로 접속을 하게 되면 단말 30300으로 연결이 되게 됩니다.
adb forward tcp:10300 tcp:30300

PC 프로그램 측

localhost는 PC자신을 의미하고 10300 포트로 접속하기위해 소켓을 만듭니다.
라인단위씩 주고 받기 위해서 stream에 연결하였습니다.

            socket = new Socket("localhost", 10300);
            out = new PrintWriter(socket.getOutputStream(), true);
            //in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            sc = new Scanner(socket.getInputStream());

아래코드는 종료될때 소켓을 닫아주기 위해서 존재합니다.

            // add a shutdown hook to close the socket if system crashes or exists unexpectedly
            Thread closeSocketOnShutdown = new Thread() {
                public void run() {
                    try {
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            };

            Runtime.getRuntime().addShutdownHook(closeSocketOnShutdown);

Socket scanner에 데이터가 있으면 화면에 출력하는 문장입니다.

        while(t.sc.hasNext()) {
        System.out.println(System.currentTimeMillis() + " / " + t.sc.nextLine());
        }


댓글 1개:

  1. 덕분에 상당부분 고민하던 부분이 대부분 해결되었습니다. 감사합니다.!!

    답글삭제