Приложение Android зависает при использовании ObjectInputStream. Проблема клиент-сервер

Я пытаюсь установить клиент-серверные отношения между устройством Android (эмулятором) и моим ноутбуком. Похоже, что сокет настроен правильно, так как данные сначала передаются от клиента к серверу, но программа зависает на стороне клиента при попытке использовать ObjectInputStream для установления входного потока.

Вот код, используемый для настройки сервера на ноутбуке:

try{
        providerSocket = new ServerSocket(6666);
        connection = providerSocket.accept();

        out = new ObjectOutputStream(connection.getOutputStream());
        out.flush();
        System.out.println("output stream established");

        in = new ObjectInputStream(connection.getInputStream());
        System.out.println("input stream established");

        try{
            message = (String)in.readObject();
            System.out.println("client>" + message);
            sendMessage("Thanks for the message!");
        }
        catch(ClassNotFoundException classnot){
            System.err.println("Data received in unknown format");
        }
    }
catch(IOException ioException){
    ioException.printStackTrace();
}

Вот соответствующий код для устройства Android. Метод updatePhotos вызывается, когда нажимается определенная кнопка, вы можете видеть, что текст кнопки изменяется, чтобы помочь определить, где останавливается код.

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    new Thread(new ClientThread()).start();
}
public void updatePhotos(View view){
    Button button = (Button)findViewById(R.id.button7);
    try {
        String msg = "Hello";
        ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
        out.flush();

        out.writeObject(msg);
        out.flush();

        button.setText("Establishing Input Stream");
        ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
        button.setText("Input stream established");

        msg = (String)in.readObject();
        button.setText(msg);

        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
}

class ClientThread implements Runnable {
    @Override
    public void run() {
        try {
            InetAddress serverAddr = InetAddress.getByName(SERVER_IP);
            socket = new Socket(serverAddr, SERVERPORT);
        } catch (UnknownHostException e1) {
            e1.printStackTrace();
        } catch (IOException e1) {
            e1.printStackTrace();
        }
    }
}

Таким образом, сначала запускается серверная программа, а затем приложение Android запускается на эмуляторе. ClientThread запускается, когда начинается первая активность приложения и успешно устанавливается подключение к сокету.

Затем я нажимаю кнопку, и программы запускаются до тех пор, пока текст кнопки не будет читать «Установка входного потока», а консоль Eclipse не будет читать:

выходной поток установлен

входной поток установлен

клиент>Здравствуйте

сервер>Спасибо за сообщение!

Ясно, что программа останавливается на строке, которая создает ObjectInputStream для клиента, хотя данные отправляются клиенту с сервера. Сообщений об ошибках нигде нет. Что я здесь делаю неправильно?


person Toast    schedule 07.01.2014    source источник


Ответы (1)


Не создавайте новый набор потоков каждый раз, когда хотите что-то отправить. Используйте одни и те же ObjectInputStream и ObjectOutputStream на протяжении всего срока службы сокета на обоих концах. На данный момент у вас есть один ObjectOutputStream на сервере и несколько ObjectInputStreams на клиенте. После первого раза конструктор ObjectInputStream заблокируется в ожидании заголовка потока объектов, который никогда не прибудет. См. Javadoc.

NB ваш сервер оставляет желать лучшего, начиная с того, что он никогда не закрывает принятый сокет. Он должен запускать новый поток для каждого принятого сокета и выполнять весь ввод-вывод, включая построение потока, в этом потоке.

person user207421    schedule 07.01.2014
comment
Спасибо за ответ. Я переместил настройки ObjectInputStream и ObjectOutputStream в ClientThread, и теперь он устанавливает их обоих. Теперь метод кнопки имеет только следующее: String msg = "Hello"; out.writeObject(msg); button.setText("Message sent"); msg = (String)in.readObject(); button.setText("Message Received"); Сервер успешно получает сообщение, но клиент теперь останавливается на строке in.readObject(). Любая идея, почему он не читает сообщение, отправленное с сервера? - person Toast; 08.01.2014