Форум программистов, компьютерный форум, киберфорум
Наши страницы
Java: Сети
Войти
Регистрация
Восстановить пароль
 
Njula
36 / 3 / 0
Регистрация: 21.05.2018
Сообщений: 111
1

Прием сообщений от сервера

18.08.2018, 12:34. Просмотров 298. Ответов 8
Метки нет (Все метки)

Здравствуйте, уважаемые форумчане! Такая проблема возникла. Пишу клиент-серверное приложение, в котором сервер должен через определенный интервал времени отсылать клиенту сообщения, а тот должен их ждать и выводить. Смотрел примеры реализаций чатов, вроде все то же, но у меня, когда в клиенте ввожу бесконечный цикл ожидания сообщений от сервера, клиент зависает. Без цикла, через определенный интервал сообщение передается, но естественно одно. Подскажите, пожалуйста где, в чем я не прав? Вот код:
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class ServerTest {
    public static void main(String[] args) throws IOException {
        ServerSocket server = new ServerSocket(1234);
        System.out.println("Сервер стартовал");
        try {
            while (true) {
                Socket incoming = server.accept();
                System.out.println("Соединение установлено");
                Runnable r = new ThreadedHandlerTest(incoming);
                Thread t = new Thread(r);
                t.start();
            }
        } finally {
            server.close();
        }
 
    }
}
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class ThreadedHandlerTest implements Runnable
{
    ServerSocket server;
    Socket incoming;
    PrintWriter out;
    Scanner in;
    RandomAccessFile raf;
    private FileReader reader;
    private String file;
    private int count;
    private String id = "id1";
    private static final int DELAY = 5000;
    private String event;
 
 
    public ThreadedHandlerTest(Socket incoming) throws IOException
    {
        this.incoming = incoming;
    }
    
    @Override
    public void run()
    {
        try
        {
            out = new PrintWriter(incoming.getOutputStream());
            Timer timer = new Timer(DELAY, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
 
                   out.println(count++);
                   out.flush();
 
                }
            });
            timer.start();
        }catch(IOException e)
        {
            e.printStackTrace();
        } 
    }
}
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
public class ClientTest extends Application {
    Socket socket;
    Scanner in;
    PrintWriter out;
    String text;
    Stage window;
    Scene scene;
    Group pane;
    Label event;
    VBox layout;
    BorderPane borderPane;
 
    @Override
    public void start(Stage primaryStage) throws Exception
    {
        borderPane = new BorderPane();
        socket = new Socket("localhost",1234);
        in = new Scanner(socket.getInputStream(),"UTF-8");
        out = new PrintWriter(new BufferedOutputStream(socket.getOutputStream()));
        window = primaryStage;
        pane = new Group();
        layout = new VBox(20);
        layout.setAlignment(Pos.CENTER);
        event = new Label();
 
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                Platform.runLater(new Runnable() {
                    @Override
                    public void run() {
                        while (!socket.isInputShutdown()) {
                            if (in.hasNextLine())
                                event.setText(in.nextLine());
                        }
                    }
                });
            }
        });
        t.start();
 
        layout.getChildren().addAll(event);
        pane.getChildren().addAll(layout);
        borderPane.setCenter(pane);
        scene = new Scene(borderPane, 500,200);
        window.setScene(scene);
        window.setTitle("Event reminder");
        window.show();
        window.setOnCloseRequest(e->
                {
                    out.close();
                    in.close();
                    try
                    {
                        socket.close();
                    } catch (IOException e1)
                    {
                        e1.printStackTrace();
                    }
                }
        );
    }
 
    public static void main(String[] args) throws IOException {
        launch(args);
    }
}
0
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
18.08.2018, 12:34
Ответы с готовыми решениями:

Получение сообщений от сервера к клиенту
Всем привет.Не могу решить проблему передачи от сервера к клиенту сообщений,состоящих их нескольких...

Асинхронные сокеты: Как организовать разделение на прием сообщений и прием файлов
Изучив синхронные сокеты, перешел к изучению асинхронных. Столкнулся вот с чем, как, используя...

Отправка и прием сообщений
Здравствуйте! Мне нужно написать приложение, которое позволяло бы общаться его пользователям. При...

Прием почтовых сообщений
Нашел такой код сделал тестовый почтовый ящик и решил попробовать: procedure...

Прием сообщений IdIRC
Здравствуйте. Как сделать прием сообщений? IdIRC. Коннект идет по кнопке...

8
Welemir1
Автоматизируй это!
1096 / 644 / 256
Регистрация: 30.03.2015
Сообщений: 2,429
18.08.2018, 16:51 2
Njula, не нравится мне твой ЭкшнЛистенер, попробуй тот код где таймер и отправка заменить на простой цикл с тред слип и отправкой - просто проверить как будет работать.
еще помни о правиле для всех таких приложений - закрывать все стримы и сокеты, а также сделать возможность нормального завершения как клиента так и сервера. скажем чтобы сервер отключался получив какую-нибудь команду, сбрасывая все соединения. клиент, если привязан к ГУИ то по нажатию кнопки.
1
Njula
36 / 3 / 0
Регистрация: 21.05.2018
Сообщений: 111
18.08.2018, 22:46  [ТС] 3
Спасибо, Welemir1, за быстрый ответ, не смотря на выходные! Заменил таймер на цикл со sleep. Клиент в общем работает так же. Добавил кнопку сброса. Если убрать цикл ожидания сообщения от сервера, то окно оживает через указанный интервал - появляется сообщение и кнопка. Интересно, что независимо от того, где расположить sleep, до отправки сообщения или после - сначала окно не отвечает, потом все появляется. С циклом - висит проклятый).
0
JIeIIIa
951 / 571 / 135
Регистрация: 23.05.2012
Сообщений: 7,370
19.08.2018, 01:06 4
Njula, впечатление, что ГУИ и ожидание сообщений от сервера у Вас живут в одном потоке.
1
19.08.2018, 01:06
Welemir1
Автоматизируй это!
1096 / 644 / 256
Регистрация: 30.03.2015
Сообщений: 2,429
19.08.2018, 07:29 5
Njula, присоединяюсь к предыдущему оратору! не отвечающее окно - первый признак, что главный поток (в котором и гуи) работает и с запросами сетевыми, что недопустимо. Я, увы, давно ничего графического не трогал, но помню что в свое время вызывал какую то специальную конструкцию, для вызова тяжеловесных операций в отдельном потоке. В целях тестирования можно пока сервер/клиент заменить на обычный тред слип, просто добиться, чтобы твой гуи не зависал при нажатиях кнопок.
1
Njula
36 / 3 / 0
Регистрация: 21.05.2018
Сообщений: 111
19.08.2018, 09:42  [ТС] 6
Написал:
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
new Thread(new Runnable() {
            @Override
            public void run() {
                Platform.runLater(new Runnable() {
                    @Override
                    public void run() {
                        while (flag){
                            event.setText(Integer.toString(counter++));
                            try {
                                Thread.sleep(5000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                });
            }
        }).start();
Висит... Но я же создаю отдельный поток. Как так?
0
Welemir1
Автоматизируй это!
1096 / 644 / 256
Регистрация: 30.03.2015
Сообщений: 2,429
19.08.2018, 09:54 7
Njula, попробуй ранЛейтер вызывать в главном потоке, не создавай для него отдельный. И там точно только один метод ранЛейтер для отдельного запуска? вроде как то по другому назывался нужный метод...
1
Njula
36 / 3 / 0
Регистрация: 21.05.2018
Сообщений: 111
19.08.2018, 12:46  [ТС] 8
Попробовал использовать конструкцию:
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Task task = new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                while (flag) {
                    event.setText(Integer.toString(counter++));
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                return null;
            }
        };
        new Thread(task).start();
И через интервал стал получать исключение Exception in thread "Thread-4" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-4. Это то, от чего я избавился применив Platform.runLater. Но текст в label появляется сразу, ГУИ не зависает...

Добавлено через 4 минуты
Цитата Сообщение от Welemir1 Посмотреть сообщение
попробуй ранЛейтер вызывать в главном потоке, не создавай для него отдельный
- ок, сделал, висит. Буду дальше копать интернет...

Добавлено через 1 час 43 минуты
Заработало! Вот, что я нарыл:
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Task task = new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                while (flag) {
                    updateMessage(Integer.toString(counter++));
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                return null;
            }
        };
        new Thread(task).start();
        event.textProperty().bind(task.messageProperty());
Очень на мой взгляд хорошее решение - использование связывания messageProperty задания Task со свойством Label. Не требуется setText. Попробую еще использовать TimeLine, так, для опыта...

Добавлено через 19 минут
В общем образовалась некоторая ясность. Все длительные операции, не затрагивающие узлы графа сцены, например с использованием sleep, нужно делать в Task. Если нужно изменять узлы, то, получать результат из Task, и ставить в очередь с помощью, Platform.runLater, который отправляет данные в основной поток javaFX, ибо только из него и можно изменять узлы. Как-то так...

Добавлено через 15 минут
TimeLine тоже работает, но перед появлением первого значения в течение интервала ничего не отображается и только потом начинается отсчет. С Task работает лучше.
2
Njula
36 / 3 / 0
Регистрация: 21.05.2018
Сообщений: 111
20.08.2018, 16:22  [ТС] 9
А вот передача сообщений от сервера через интервал времени не выходит... значит, в клиенте я пишу:
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
Task task = new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                while (flag){
                    updateMessage(finalInput.readUTF());
                }
                return null;
            }
        };
        Thread t = new Thread(task);
        t.setDaemon(true);
        t.start();
        event.textProperty().bind(task.messageProperty());
в обработчике потока на стороне сервера:
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 public void run()
    {
        try
        {
            DataOutputStream out = new DataOutputStream(new BufferedOutputStream(incoming.getOutputStream()));
            while (incoming.isConnected())
            {
                out.writeUTF("Hi");
                //Thread.sleep(2000);
                out.writeUTF("Bye");
            }
        }catch (IOException e)
        {
            e.printStackTrace();
        }
    }
Если раскоментировать sleep - в окне ничего не отображается. А так сообщения передаются - непрерывно сменяют друг друга. Прошу помощи знатоков...

Добавлено через 18 минут
Находил в инете решение похожей задачи с помощью swing.Time, но у меня не идет...

Добавлено через 1 минуту
Хотелось бы понять...

Добавлено через 2 часа 29 минут
Может я использую не те инструменты... Мне нужно пинговать подключившихся клиентов, и если те не отвечают, удалять их из списка юзеров онлайн. Это часть задачи.
0
20.08.2018, 16:22
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
20.08.2018, 16:22

Клиент-сервер, прием сообщений
Доброго времени суток. Писал в &quot;С++ для начинающих&quot;, но там никто мне не ответил... Есть...

C# SerialPort Неполный прием сообщений
Добрый день. Долго искал решение своей проблемы, но поиски оказались тщетны. Задача: организовать...

TcpServer. Прием сообщений от клиентов
Доброго времени суток. Есть сервер: #include &quot;server.h&quot; #include &quot;ui_server.h&quot; #include...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
9
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.
Рейтинг@Mail.ru