0

私はネットワーキング演習用の Android アプリに取り組んでおり、あらゆる種類の問題を抱えています。私は自分のコンピューターで実行している動作中の C サーバーを持っています。私が書いているアプリは、サーバーに接続し、認証し、サーバーからクライアントへのファイル転送を開始することを目的としています。私は Android の初心者であり、UI スレッドのブロックが一般的に禁止されていることをごく最近知りました。

これを支援するために AsyncTask を作成しました。ただし、呼び出すと完全に完全に失敗します。ただし、目立って失敗するわけではありません。私が目にする唯一の問題は、私のメインスクリーンが縮小して奇妙な動きをすることです。UI スレッドが完全にブロックされ、OS からアプリが応答していないと通知されることがあります。これは、ブロックしているアクションをスレッド化しているため、意味がありません。

これは、AsyncTask に使用しているコードです。

private class LoginTask extends AsyncTask<String, Void, Boolean> {

    @Override
    protected Boolean doInBackground(String... input) {
        int count = input.length;
        if (count != 4)
            return false;
        String ipAddress = input[0];
        int portNumberInt = Integer.parseInt(input[1]);
        String username = input[2];
        String password = input[3];
        // Step 0: Establish a connection to the server
        PrintWriter out;
        BufferedReader in;
        try {
            serverSocket = new Socket(ipAddress, portNumberInt);
            out = new PrintWriter(serverSocket.getOutputStream(), true);
            in = new BufferedReader(new InputStreamReader(serverSocket.getInputStream()));
        } catch (IOException e) {
            ((TextView)findViewById(R.id.textView1)).setText(e.getMessage());
            ((TextView)findViewById(R.id.textView2)).setText("");
            return false;
        }
        // Step 1: send "Authorize" to the server
        out.print("Authorize");
        // Step 2: server sends a random 64 character challenge string
        char[] buffer = new char[64];
        String challenge = null;
        try {
            in.read(buffer);
            challenge = new String(buffer);
        } catch (IOException e) {
            ((TextView)findViewById(R.id.textView1)).setText(e.getMessage());
            ((TextView)findViewById(R.id.textView2)).setText("");
            return false;
        }
        challenge = username + password + challenge;
        // Step 3: Compute MD5 hash of username + password + challenge and send it to the server
        MessageDigest md5;
        try {
            md5 = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            return false;
        }
        byte[] digest = md5.digest(challenge.getBytes());
        out.print(digest);
        // Step 4: Server computes the same hash, determines whether or not to accept the connection
        String authResult;
        try {
            in.read(buffer);
            authResult = new String(buffer);
        } catch (IOException e) {
            ((TextView)findViewById(R.id.textView1)).setText(e.getMessage());
            ((TextView)findViewById(R.id.textView2)).setText("");
            return false;
        }
        if (authResult.equals("Pass")) {
            return true;
        } else {
            return false;
        }
    }

}

これは、AsyncTask を呼び出すコードです。

public boolean authenticate(final String ipAddress, final int portNumberInt, final String username, final String password) {
    try {
        Toast.makeText(getApplicationContext(), "Starting async task...", Toast.LENGTH_LONG).show();
        boolean result = new LoginTask().execute(ipAddress, Integer.toString(portNumberInt), username, password).get();
        Toast.makeText(getApplicationContext(), "Async task done!", Toast.LENGTH_LONG).show();
        return result;
    } catch (InterruptedException e) {
        Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();
        return false;
    } catch (ExecutionException e) {
        Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();
        return false;
    }

}

この問題の原因は何ですか? サーバーを実行していますが、接続が確立されたことを示す兆候がありません。この場合、私のコードは決してブロックされるべきではありません...そうですか?

4

2 に答える 2

1

あなたの問題に決定的な答えを出すことはできませんが、ここで修正したい問題がいくつかあります。あなたの質問からの2つの引用...

UI スレッドのブロックが一般的に禁止されていることをごく最近知りました。

実際には、「一般的に」禁止されているだけでなく、絶対に行わないでください。

...OS は、アプリが応答していないことを通知します。これは、ブロックしているアクションをスレッド化しているため、意味がありません。

あなたのauthenticateメソッドのこの行のために正確ではありません...

boolean result = new LoginTask().execute(<cut-for-clarity>).get();

get()基本的に結果を「待機」するメソッドを使用してAsyncTask、非同期タスクを実行するための呼び出しを同期タスクに変えています。

を使用get()してネットワーク操作をAsyncTask実行することは、単に UI スレッドでコードを実行するのと同じくらい悪い可能性があります。なぜメソッドAsyncTaskがあるのか​​ 理解できませんでした。get(...)

私が目にする次の問題は、次のコードにあります...

try {
    serverSocket = new Socket(ipAddress, portNumberInt);
    out = new PrintWriter(serverSocket.getOutputStream(), true);
    in = new BufferedReader(new InputStreamReader(serverSocket.getInputStream()));
} catch (IOException e) {
    ((TextView)findViewById(R.id.textView1)).setText(e.getMessage());
    ((TextView)findViewById(R.id.textView2)).setText("");
    return false;
}

まず、catchブロックは のみを探していIOExceptionます。ソケットを作成すると、 がスローされる可能性もありますUnknownHostException。あなたの作成PrintWriterもスローNullPointerExceptionなどなど

次に、catchブロックで 2 つの のテキストを設定しようとしていますTextView。スレッド化の 2 番目の黄金律 (UI スレッドをブロックしないことは別として) は、UI スレッド以外のスレッドから UI 要素を操作しようとしないことです。これは機能しません。

だから基本的に

  1. 少なくとも関連する例外を処理するようにコードをクリーンアップします。必要try{...} catch(Exception e) {...}に応じて、すべての周りにジェネリックを配置しdoInBackground(...)ます。
  2. get()の方法を使用しないでください。AsyncTask
  3. UI 要素を操作しようとするものはすべて取り除きます。doInBackground(...)
  4. logcat を調べて、何が失敗しているか、どの行にあるかを確認してください。

編集:

より一般的には、AsyncTask から UI スレッドに情報を戻すにはどうすればよいですか?

これが、UI スレッドで実行されるonPostExecute(...)メソッドの要点です。AsyncTask

doInBackground(...)認証だけでなく、必要なファイルのダウンロードにも使用します。問題がある場合はfalse、結果としてに渡し、onPostExecute(...)そのメソッドに何らかの警告またはエラー メッセージを作成させてから、クリーンアップします。

于 2012-04-05T00:31:29.803 に答える
0

コンピューターで C サーバーを実行している場合は、Android のクライアントが必要です。クライアントはソケットを使用します。ServerSocket を使用しています...

于 2012-04-05T21:37:52.780 に答える