2

ユーザーの入力をサーバーに投稿するだけのAndroidソケットデモを作成します。Wi-Fi接続を介してAndroidクライアントからソケットを確立すると、すべてがうまくいき、サーバーはAndroidクライアントから送信されたメッセージを受信できます。問題は、電話のWIFIを閉じることですが、ソケットは例外なく書き込みできます。

Android クライアントのコード:

public class MyActivity extends Activity {
    private SocketHandlerThread thread;

    /**
     * Called when the activity is first created.
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        thread = new SocketHandlerThread("ScoketTest");
        thread.start();
    }

    class SocketHandlerThread extends HandlerThread {
        private Socket socket;
        private Handler handler;

        public SocketHandlerThread(String name) {
            super(name);
        }

        public SocketHandlerThread(String name, int priority) {
            super(name, priority);
        }

        @Override
        public void run() {
            try {
                socket = new Socket("192.168.60.184", 1990);
            } catch (IOException e) {
                Log.e("SocketTest", e.getLocalizedMessage(), e);
            }
            super.run();
        }

        Handler getHandler() {
            if (handler == null) {
                handler = new Handler(getLooper());
            }
            return handler;
        }

        void send(final String text) {
            Runnable runnable = new Runnable() {
                public void run() {
                    Log.e("SocketTest", "Start send text: " + text);
                    try {
                        socket.getOutputStream().write((text + "\n").getBytes());
                        socket.getOutputStream().flush();
                    } catch (Exception e) {
                        Log.e("SocketTest", e.getLocalizedMessage(), e);
                    }
                    Log.e("SocketTest", "Text has been send:" + text);
                }
            };
            getHandler().post(runnable);
        }

        @Override
        protected void onLooperPrepared() {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    findViewById(R.id.button).setEnabled(true);
                }
            });
        }
    }

    public void send(View view) {
        String text = ((EditText) findViewById(R.id.text)).getText().toString();
        thread.send(text);
    }
}

サーバーのコード:

public class SocketTestServer {
    ServerSocket serverSocket;

    SocketTestServer() throws IOException {
        serverSocket = new ServerSocket(1990);
    }

    void start() throws IOException {
        Socket clientSocket = serverSocket.accept();
        clientSocket.getInputStream();
        PrintWriter out = new PrintWriter(System.out, true);
        BufferedReader in =
                new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
        String inputLine;
        while ((inputLine = in.readLine()) != null) {
            out.println(inputLine);
        }
    }

    public static void main(String[] args) throws IOException {
        SocketTestServer server = new SocketTestServer();
        server.start();
    }
}

私はいくつかの電話で試します。Galaxy Nexus(4.2.1) では予期したとおりに例外がスローされましたが、一部の MOTO または HTC 電話ではソケットが例外なく書き込みを行うことができます。どのタイプの電話でもソケット接続が切断されたことを知るにはどうすればよいですか?

任意の提案をいただければ幸いです。

ps Connective Change Broadcast は知っていますが、ブロードキャストを受信する前に、クライアントが壊れたソケットを介して何らかのメッセージを書き込んでいる可能性があります。

アプリケーション プロトコルに受信チェックを追加することでメッセージ損失の問題を解決できますが、私は TCP プロトコルが約束するトランスポート層での信頼性を保証することを好みます。

4

2 に答える 2

0

ソケットでWriter&IOExceptionを使用していますが、正常に動作します。これを試して:

public static void sendUTF(String str)
    {
        try
        {
            outWriter.write(str + '\n');
            outWriter.flush();
        } 
        catch (IOException e)
        {
            e.printStackTrace();
            outServ.setText("Connection lost!");
        }
    }

public static Writer outWriter = new OutputStreamWriter(outputStream, "UTF-8");
于 2013-01-07T08:54:55.213 に答える
0

これはTCPスタック(OSレベル)の問題であり、解決が難しい問題です。サーバーが接続を失った場合にも発生します(ソケットを開いた後にサーバーを再起動しようとすると、クライアントは気付かないでしょう)...次にソケットを介してパケットを送信すると、「壊れたパイプエラー」が発生します。

したがって、次の 2 つのシナリオがあります。

1- クライアントが情報を送信するときの壊れたパイプ。

このシナリオでは、IOException をキャプチャし、接続を開くために再試行する必要があります (再試行ポリシーを定義する必要があります)。

2-サーバーが接続を失ったときの壊れたパイプ

サーバーが接続を失ったとき、クライアントはそれに気づきません。このシナリオでは、定期的にサーバーにパケットを送信し (ポーリング手法)、接続が失われた場合に備えて再接続を試みる必要があります。これは、サーバーから更新を受信する場合にのみ必要です。トラフィックが常にクライアント -> サーバーである場合は、シナリオ 1 のみが適用されます。

于 2013-01-18T22:25:48.200 に答える