powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Java [игнор отключен] [закрыт для гостей] / Клиент-сервер, поругайте код сервера.
11 сообщений из 11, страница 1 из 1
Клиент-сервер, поругайте код сервера.
    #38930140
korshun
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Тут есть много знающих людей, посмотрите пожалуйста, может какой-нибудь криминал увидите.
Опыта пока мало, сильно не пинайте))) Но вроде в целом конструкция работает.
Единственное, что заметил - при подключении одновременно 3-5 клиентов скорость передачи заметно падает, частенько кто-то отваливается по таймауту: s1.setSoTimeout(ACCEPT_TIMEOUT * 1000); Устанавливаю его 30 сек, может есть смысл сделать больше ?
Заранее благодарю!




Код: 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.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
274.
275.
276.
277.
278.
279.
280.
281.
282.
283.
284.
285.
286.
287.
288.
289.
290.
291.
292.
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;


public class Root {

    private int PORT;
    private int PORT_FILES;
    private int ACCEPT_TIMEOUT;
    public static String COBA_PATH_NAME;

    private final String CONFIG_FILE = "coba.conf";
    private HashMap<String, String> params = new HashMap<>();

    private Root() {
        readFile();
        setParams();
    }




    private void readFile(){
        String line;
        try(BufferedReader br = new BufferedReader(new FileReader(CONFIG_FILE))) {
            while((line = br.readLine()) != null){

                if(line.length() > 0 && !line.startsWith("#") && line.contains("=")) {
                    String parts[] = line.split("=");
                    params.put(parts[0], parts[1]);
                }

            }

        } catch (IOException e) {
            e.printStackTrace();
            Logging.writeToFile("error", "Ошибка доступа к файлу конфига");
        }
    }


    private void setParams() {
        PORT =                      Integer.parseInt(params.get("CONNECT_PORT"));
        PORT_FILES =                Integer.parseInt(params.get("DOWNLOAD_PORT"));
        ACCEPT_TIMEOUT =            Integer.parseInt(params.get("ACCEPT_TIMEOUT"));
        COBA_PATH_NAME =            params.get("IMG_PATH");
    }






    private void serverStart() {

        ServerSocket s = null, s1 = null;

        try {

            s = new ServerSocket(PORT);
            s1 = new ServerSocket(PORT_FILES);
            s1.setSoTimeout(ACCEPT_TIMEOUT * 1000);

            SystemTrayIcon.createIcon();

            System.out.println("Сервер запущен");

            while (true) {

                Socket client = s.accept();

                new ClientConnect(s1, client).start();

                System.out.println("Клиент подключился: " + client);
                Logging.writeToFile("access", "Клиент подключился: " + client);

            }

        } catch (IOException e) {
            e.printStackTrace();
            Logging.writeToFile("error", e.getMessage());
        } finally {
            try {
                if (s != null) {
                    s.close();
                }
                if (s1 != null) {
                    s1.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
                Logging.writeToFile("error", e.getMessage());
            }
        }

    }


    public static void main(String[] args) {

        new Root().serverStart();

    }

}




class ClientConnect
    extends Thread {

    private ServerSocket s1;
    private Socket client;
    private String deviceId;
    private int filesCount;

    public ClientConnect(ServerSocket s1, Socket client) {
        this.s1 = s1;
        this.client = client;

        System.out.println("Сессия для " + client + " открыта");
    }

    public void run(){

        try (
                BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
                PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(client.getOutputStream())), true)
        ) {

            ArrayList<String> listNewFiles = new ArrayList<>();

            String query;

            while (true) {

                TimeUnit.MILLISECONDS.sleep(1000);

                query = in.readLine();



                if(query == null) {
                    System.out.println("query == null   ------   DISCONNECT");
                    break;
                }




                //Клиент отсоединился
                if (query.equals("disconnect")) {
                    out.println("close");
                    out.flush();

                    System.out.println(deviceId + ": Обновление завершено, клиент отключился");

                    break;
                }




                //Клиент сделал запрос на кол-во новых файлов
                if (query.startsWith("getFilesNew")) {

                    String lastUpdateDate[] = query.split(":");
                    deviceId = lastUpdateDate[2];
                    System.out.println(deviceId + ": запрашивается количество новых файлов");

                    Logging.writeToFile(deviceId, "access", "Сессия открыта");
                    Logging.writeToFile(deviceId, "access", "Запрашивается количество новых файлов");


                    for (File file : new File(Root.COBA_PATH_NAME).listFiles()) {

                        if (file.isFile()) {

                            if ((Long.parseLong(lastUpdateDate[1]) - file.lastModified()) < 0) {

                                listNewFiles.add(file.getName());

                            }

                        }

                    }

                    System.out.println(deviceId + ": Новых файлов " + listNewFiles.size());
                    Logging.writeToFile(deviceId, "access", "Новых файлов " + listNewFiles.size());

                    out.println(listNewFiles.size());
                    out.flush();

                    filesCount = listNewFiles.size();

                    continue;

                }


                //Клиент сделал запрос на скачивание
                if (query.equals("download") & filesCount > 0) {

                    System.out.println(deviceId + ": Получен запрос на скачивание");
                    Logging.writeToFile(deviceId, "access", "Получен запрос на скачивание");

                    Socket client1;

                    for (String newFile : listNewFiles) {

                        String tmpPath = Root.COBA_PATH_NAME + File.separator + deviceId;
                        File fileName = new File(tmpPath + File.separator + newFile);

                        Logging.writeToFile(deviceId, "access", "Шифруем: " + newFile);

                        ImgEncode
                                .getInstance(newFile, Root.COBA_PATH_NAME, tmpPath)
                                .encodeImg();

                        out.println(newFile);
                        out.flush();

                        out.println(fileName.length());
                        out.flush();

                        System.out.println(deviceId + ": Ожидаем подключения для скачивания ...");
                        Logging.writeToFile(deviceId, "access", "Ожидаем подключения для скачивания ...");

                        client1 = s1.accept();

                        System.out.println(deviceId + ": Клиент для скачивания подключился, отправляем: " + newFile);
                        Logging.writeToFile(deviceId, "access", "Клиент для скачивания подключился, отправляем: " + newFile);

                        FileInputStream fis = new FileInputStream(fileName);
                        BufferedInputStream bis = new BufferedInputStream(fis);
                        DataOutputStream dos = new DataOutputStream(client1.getOutputStream());

                        byte[] buffer = new byte[32 * 1024];
                        int count, total = 0;

                        while ((count = bis.read(buffer, 0, buffer.length)) != -1) {
                            total += count;
                            dos.write(buffer, 0, count);
                            dos.flush();
                        }

                        System.out.println(deviceId + ": Файл " + newFile + " передан");
                        Logging.writeToFile(deviceId, "access", "Файл " + newFile + " передан");

                        fis.close();
                        bis.close();
                        dos.close();

                        client1.close();

                        fileName.delete();

                        System.out.println(deviceId + ": Клиент для скачивания отключился");
                        Logging.writeToFile(deviceId, "access", "Клиент для скачивания отключился");

                    }

                }


            }

        } catch (InterruptedException | IOException e) {
            e.printStackTrace();
            Logging.writeToFile("error", e.getMessage());
        }

        finally {
            try {
                client.close();
                System.out.println(deviceId + ": Соединение закрыто. client.close()");
                Logging.writeToFile(deviceId, "access", "Соединение закрыто");
            } catch (IOException e) {
                e.printStackTrace();
                Logging.writeToFile("error", e.getMessage());
            }
        }

    }

}


...
Рейтинг: 0 / 0
Клиент-сервер, поругайте код сервера.
    #38930211
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
korshunНо вроде в целом конструкция работает.
Единственное, что заметил - при подключении одновременно 3-5 клиентов скорость передачи заметно падает

Сами себе противоречите.


Код: 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.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
    private int PORT;//Нарушение общепринятых coding convention. Не константа.
    private HashMap<String, String> params = new HashMap<>(); //Нарушение Best Practices. Тип должен быть Map.
    private Root() {//Странное имя класса, кстати.

    private void readFile(){
        //OMFG или "смотри мама, я написал java.util.Properties" в 5 строк.
    }

    //Apache Commons Configuration
      PORT =                      Integer.parseInt(params.get("CONNECT_PORT"));

     ServerSocket s = null, s1 = null; //Нарушение общепринятых coding convention

      SystemTrayIcon.createIcon(); // GUI в классе и методе сервера. Оригинально.

            while (true) { //Штатной остановки не предусмотрено?
                new ClientConnect(s1, client).start(); //О! Новый поток на каждого клиента. 
 
// Так как конкретно в этом проекте логируют?
              System.out.println("Сервер запущен");
              System.out.println("Клиент подключился: " + client);
              Logging.writeToFile("access", "Клиент подключился: " + client);

//Сюрприз! ServerSocket и Socket тоже реализуют Closeable\AutoCloseable
        } finally {
            try {
                if (s != null) {
                    s.close();
                }
                if (s1 != null) {
                    s1.close();
                }
        }

class ClientConnect extends Thread //Даже в JavaDoc к классу Thread рекомендуют так не делать

    private ServerSocket s1;//Подход к именованию идентификаторов ниже плинтуса. 

//Форматирование ни к черту
        try (
                BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
                PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(client.getOutputStream())), true)
        ) {

//Тип должен быть List<String>
            ArrayList<String> listNewFiles = new ArrayList<>(); //Английский тоже не мешало бы подтянуть

            while (true) { //Клиент с нами навсегда?

                TimeUnit.MILLISECONDS.sleep(1000); //Это вообще жесть. НАФИГА???

                query = in.readLine(); //Тут есть тонкий момент с кроссплатформой. У Windows и Linux разные символы переноса строк. 

                if(query == null) {
                    System.out.println("query == null   ------   DISCONNECT");
                    break; //И почему бы не сделать это условием цикла?
                }
                     
                //Ах! У нас есть штатный выход!!
                //Клиент отсоединился
                if (query.equals("disconnect")) {
                    break;
                }



                //И на каждый новый query мы будем добавлять по новому if блоку?
                if (query.startsWith("getFilesNew")) {

                    String lastUpdateDate[] = query.split(":"); //Протокол обмена данными стоило реализовать отдельным классом.

                    //А если такого пути нет?
                    for (File file : new File(Root.COBA_PATH_NAME).listFiles()) {

                        if (file.isFile()) { //isFile() подразумевает exists() ?
                            //Такие замороченные условия имеет смысл инкапсулировать во внятно именованный метод
                            if ((Long.parseLong(lastUpdateDate[1]) - file.lastModified()) < 0) {

                                //FileFilter, не не слышал
                                listNewFiles.add(file.getName());


                    Socket client1; //Снова отличное именование. Почему 1, а не 2?


                    //Вместо конкатенации и File.separator стоит использовать классы Path, File
                        String tmpPath = Root.COBA_PATH_NAME + File.separator + deviceId;
                        File fileName = new File(tmpPath + File.separator + newFile);


                        //Как мы ловко подзабили на try with resource. А так хорошо начинали.
                        FileInputStream fis = new FileInputStream(fileName);
                        BufferedInputStream bis = new BufferedInputStream(fis);
                        //Этот класс тут вообще задлянафига?
                        DataOutputStream dos = new DataOutputStream(client1.getOutputStream());

                        byte[] buffer = new byte[32 * 1024]; //У нас уже есть BufferedInputStream, но мы упорно будем читать через свой буфер. Ачивка за двойную оптимизацию!
                        int count, total = 0; //Снова соглашения о кодировании проигнорированы

                        //Apache Commons IO? А где это?
                        while ((count = bis.read(buffer, 0, buffer.length)) != -1) {
                            total += count;
                            dos.write(buffer, 0, count);
                            dos.flush();
                        }

                        //Ой, а если выкинется исключение, то ничего этого не произойдет?
                        fis.close();
                        bis.close();
                        dos.close();
                        //Прощай клиент! Ты нам почему-то больше не нужен. 
                        client1.close();

                        //А если метод вернет false?
                        fileName.delete();

        //И снова здравствуйте
        finally {
            try {
                client.close();
                System.out.println(deviceId + ": Соединение закрыто. client.close()");
                Logging.writeToFile(deviceId, "access", "Соединение закрыто");
            } catch (IOException e) {
                e.printStackTrace();
                Logging.writeToFile("error", e.getMessage());
            }
        }




Итак вердикт
В первую очередь к изучению
Соглашения о кодировании:
https://www.google.com/search?q=Java Coding convention
Готовые opensource решения, и конечно же Maven. Не руками же их подключать.
http://commons.apache.org/
Логирование
http://habrahabr.ru/post/113145/
http://habrahabr.ru/post/130195/
Best Practices
http://www.javapractices.com/home/HomeAction.do
Очень рекомендую книжку Bitter Java

Читайте JavaDoc на ВСЕ классы и методы, которые используете.
Ну, и вот это тоже очень стоит изучать начинающим программистам
http://www.amazon.com/The-Clean-Coder-Professional-Programmers/dp/0137081073
чтобы тупо сэкономить время и не изобретать подходы к написанию понятного кода
...
Рейтинг: 0 / 0
Клиент-сервер, поругайте код сервера.
    #38930216
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
И ещё не бойтесь создавать классы и методы. Тут просто половина кода просится в отдельные методы.
...
Рейтинг: 0 / 0
Клиент-сервер, поругайте код сервера.
    #38930265
korshun
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Не в обиду остальным завсегдатаям, но на ваш отзыв в первую очередь и рассчитывал :)
Пару вопросов:

1.
Код: java
1.
new ClientConnect(s1, client).start(); //О! Новый поток на каждого клиента. 


Ну да. Насколько стало понятно из того материала, который гуглился просто в огромных кол-вах, так и предлагается делать: ждем соединения, принимаем, создаем отдельный поток и работаем с клиентом.

2.
Код: java
1.
while (true) { //Клиент с нами навсегда?


Так предусмотрены же выходы по команде клиента и по приходе пустой строки. Ну и + exception и выход в случае, если истекает время ожидания подключения.
Если я в чем то не прав, можно подробнее, ибо не понимаю, что тут не так.

3.
Код: java
1.
2.
//Прощай клиент! Ты нам почему-то больше не нужен. 
client1.close();


Может я и туплю, только не пойму где.
Если каждую итерацию цикла подключается клиент (client1 = s1.accept();), то после завершения "работы" с ним соединение разве не нужно закрывать ?
Или так вообще делать не нужно ? Как тогда ?

В целом спасибо за столь тщательный анализ))
...
Рейтинг: 0 / 0
Клиент-сервер, поругайте код сервера.
    #38930282
irbis_al
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: java
1.
class ClientConnect extends Thread //Даже в JavaDoc к классу Thread рекомендуют так не делать



М...а вот тут не понял...(Позвольте поинтересоваться в целях повышения квалификации :-) )
А Как надо?
...
Рейтинг: 0 / 0
Клиент-сервер, поругайте код сервера.
    #38930288
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
korshunНу да. Насколько стало понятно из того материала, который гуглился просто в огромных кол-вах, так и предлагается делать: ждем соединения, принимаем, создаем отдельный поток и работаем с клиентом.
Ну, в качестве первой учебной итерации, наверное, нормально. Но далее, стоит перейти на пул потоков из j.u.c.Executors
А затем и на NIO с селекторами.

Проблемы здесь две. Создание и инициализация нового потока достаточно затратная операция по сравнению с переиспользованием потоков из пула. И чем больше клиентов, тем больше лишних ресурсов тратится на запуск нового потока и переключение контекста (хотя последнее в современных ОС и железках уже хорошо оптимизировали)

Вторая проблема в количестве потоков. Чем больше сессий, тем больше потоков, чем больше потоков, тем "труднее" ОС между ними переключаться.


korshun
Код: java
1.
while (true) { //Клиент с нами навсегда?


Так предусмотрены же выходы по команде клиента и по приходе пустой строки. Ну и + exception и выход в случае, если истекает время ожидания подключения.
Если я в чем то не прав, можно подробнее, ибо не понимаю, что тут не так.
Это к вопросу о читаемости кода. Мы ввели читателя в заблуждение о том что цикл бесконечный, а потом расставили точек выхода - попробуй отыщи их все.
Условия выхода "предусмотрены" где-то там, хрен знает где ниже по коду. При этом их несколько. А попробуй теперь к этому циклу добавить проверку перед выходом из цикла, при условии что у тебя много разных этих самых выходов.
Количество выходов из цикла и метода лучше сводить к минимуму.



korshun
Код: java
1.
2.
//Прощай клиент! Ты нам почему-то больше не нужен. 
client1.close();


Может я и туплю, только не пойму где.
Если каждую итерацию цикла подключается клиент (client1 = s1.accept();), то после завершения "работы" с ним соединение разве не нужно закрывать ?
Или так вообще делать не нужно ? Как тогда ?
Не понятно почему именно здесь мы закрываем соединение. И причина этому проста - у вас логика, протокол и работа с IO намешаны в одном методе. Протокол должен явно указать что это была последняя команда. Клиент после её получения должен штатно отвалиться и поэтому мы закрываем соединение.
По вашему же коду, вот есть одна команда, вот другая, по одной мы закрываем клиента, по другой нет. А всё потому что бизнес-логика не описана отдельным кодом.
...
Рейтинг: 0 / 0
Клиент-сервер, поругайте код сервера.
    #38930302
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
irbis_al
Код: java
1.
class ClientConnect extends Thread //Даже в JavaDoc к классу Thread рекомендуют так не делать



Я соврал. В JavaDoc такого нет. Зато есть в туториалах
http://docs.oracle.com/javase/tutorial/essential/concurrency/runthread.html

irbis_alМ...а вот тут не понял...(Позвольте поинтересоваться в целях повышения квалификации :-) )
А Как надо?
Надо через Runnable.
...
Рейтинг: 0 / 0
Клиент-сервер, поругайте код сервера.
    #38930373
korshun
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Blazkowicz,

все понятно и доступно, вопросов нет, спасибо!
...
Рейтинг: 0 / 0
Период между сообщениями больше года.
Клиент-сервер, поругайте код сервера.
    #39502765
PsyDiamond
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Господа, вернёмся к нашим баранам.
Решил я продолжить эту затею с микросервисами.
и практически выснил почему данные обратно не передаются

если я для проверки возвращаю строку из java в oracle db, таким путём
Код: java
1.
2.
3.
4.
5.
6.
7.
                    while ((count = s.read(mybytearray, 0, mybytearray.length)) != -1) {
                        //int total = count;
                        baos.write(mybytearray, 0, count);
                        baos.flush();
                    }
out.print("lalala");
                    out.flush();



то я ничего не получаю обраатно. пусто и всё тут, но если я делаю так
Код: java
1.
2.
3.
4.
5.
6.
7.
while ((count = s.read(mybytearray, 0, mybytearray.length)) != -1) {
                        //int total = count;
                        baos.write(mybytearray, 0, count);
                        baos.flush();
out.print("lalala");
                    out.flush();
                    }



то получается ожидаемый результат.
как мне решить эту диллему? как я понял, после чтения закрывается входящий поток и тогда становиться не активным исходящий

что же это?
...
Рейтинг: 0 / 0
Клиент-сервер, поругайте код сервера.
    #39502774
PsyDiamond
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ой, прошу прощения. не в ту тему)
хотя может отчасти и в ту
...
Рейтинг: 0 / 0
Клиент-сервер, поругайте код сервера.
    #39502776
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ахтунг! Некропостеры со своими баранами.
...
Рейтинг: 0 / 0
11 сообщений из 11, страница 1 из 1
Форумы / Java [игнор отключен] [закрыт для гостей] / Клиент-сервер, поругайте код сервера.
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]