Почему этот ServerSocket в Andorid (подключенный к ПК через USB / ADB) принимает соединения только один раз?

#java #android #sockets #adb #serversocket

#java #Android #сокеты #adb #serversocket

Вопрос:

Ситуация: телефон Android был подключен к ПК через USB. Используя команду ADB adb forward tcp:35000 tcp:30000 , мне удается перенаправить порт.
Я хочу, чтобы компьютер отправлял свое системное время на телефон Android каждые 5 секунд в течение часа. С этой целью я выполняю программирование сокетов.

Сторона ПК в качестве клиента: (Я игнорирую код обработки исключений.)

 public void sendTime()
{
    class SendTask implements Runnable
    {
        public void run()
        {
            // Here: I store the host_socket in a member field which is: 
            // Socket host_socket = new Socket("localhost", 35000);
            ObjectOutputStream oos = new ObjectOutputStream(this.host_socket.getOutputStream()); 
            oos.writeObject(msg);
            oos.flush();
        }
    }
    // Here: private Executor exec = Executors.newCachedThreadPool();
    this.exec.execute(new SendTask());
}
 

Телефонная сторона Android в качестве сервера:

 public void getReadyForSync()
{
    ServerSocket server_socket = new ServerSocket();
    server_socket.bind(new InetSocketAddress("localhost", 30000));

    while (true)
    {
        final Socket client_socket = server_socket.accept();
        Runnable receive_task = new Runnable()
        {
            public void run()
            {
                ObjectInputStream ois = new ObjectInputStream(client_socket.getInputStream());
                Message msg = (Message) ois.readObject();
                SyncTimeFragment.this.onReceive(msg);
            }
        }; 
        // Here: private static final Executor exec = Executors.newCachedThreadPool();
        exec.execute(receive_task);
    }
}
 

Кроме того, ServerSocket устанавливается в отдельном потоке от основного потока Android с использованием AsyncTask и new ServerTask().execute() :

 public class ServerTask extends AsyncTask<String, Void, Void>
{
    protected Void doInBackground(String... params)
    {
        getReadyForSync();
        return null;
    }
}
 

Проблемы:

В моем тесте серверный сокет в телефоне Android принимает соединения с ПК только один раз.

В частности, некоторая отладочная информация выглядит следующим образом:

(1) При каждом вызове (каждые 5 секунд) sendTime() выполняется host_socket чтение:
Socket[addr=localhost/127.0.0.1,port=35000,localport=56520]

Обратите внимание: значения localport (ы) здесь одинаковы для всех sendTime() вызовов в одном выполнении, но различаются в разных исполнениях. (Я не уверен, важна ли эта информация или нет.)

(2) server_socket Чтения:
Socket[addr=localhost/127.0.0.1,port=0,localport=30000]

(3) client_socket Полученные (только один раз) server_socket чтения:
Socket[addr=/127.0.0.1,port=43890,localport=30000]

Комментарии:

1. Нет. Сервер может принимать много клиентов. Но если у вас только один клиент…

2. @greenapps Однако единственный клиент вызывал этот sendTime() метод много раз (каждые 5 секунд в течение часа). Другими словами, было выпущено много соединений с ПК, но только одно (первое) из них было принято сервером. Есть идеи?

3. Нет. Подключений не так много. Это не то же самое соединение. Вы не закрываете и не переподключаетесь для каждого вызова. Если бы вы затем поместили это в свой код, пожалуйста. Как и сейчас, //new Socket неясно, что происходит.

4. @greenapps Извините, я не совсем хорошо понимаю. Вы имеете в виду, что я каждый раз использую одно и то же соединение host_socket: Socket[addr=localhost/127.0.0.1,port=35000,localport=56520] ? Означает ли это, что я не могу отправлять разные сообщения, повторно используя соединение?

5. @greenapps Следуя вашим инструкциям, я исправил ошибку: создайте новый сокет в методе sendTime() вместо сохранения host_socket в качестве поля-члена и повторного его использования. Спасибо. Однако я не совсем понимаю, почему мы не можем повторно использовать соединение. Не могли бы вы дать некоторое объяснение в ответе. Я приму это.

Ответ №1:

После создания receive_task кода возвращается к final Socket client_socket = server_socket.accept(); So, сервер отбрасывает соединение, так как run() получает только одно сообщение. Вам тоже пришлось бы сделать while цикл run() .

Комментарии:

1. В комментариях после сообщения я исправил ошибку «плохим» способом: каждый раз создавайте новый сокет в методе sendTime() вместо сохранения host_socket в качестве поля-члена и повторного его использования. Это может вызвать проблемы с производительностью. @TassosBassoukos

2. Это также может привести к утечке ресурсов; предотвратите это, просто выполнив цикл в receive_task; не забудьте поместить все в try-finally, чтобы освободить сокеты…