PDA

Просмотр полной версии : Client-Server Application



Oscar
13.06.2005, 10:27
Вдохновлённый темой Создание сетевого приложения (http://www.developing.ru/forum/viewtopic.php?t=3483) решил написать себе что-то.

Точнее сказать пока что это графическая доска: Java Web Graphic Board (http://home.informatik.tu-muenchen.de/~skrypnyo/painter/)

Клиентскую часть я сделал, как Java-Applet (можно рисовать на Canvas), серверную - php (почему? Потому что большинство веб-серверов его поддерживает).

Код апплета, кому интересно, можно глянуть тут: Painter.java (http://home.informatik.tu-muenchen.de/~skrypnyo/painter/Painter.java)

Серверная часть сейчас очень проста:
По POST она принимает линии (4 int) и пишет в файл их и время добавления.
При обращении клиентов считывает всё, после последней метки считывания.

-----
1. Информацию пересылаю по HTTP - медленно,
через Sockets было бы, наверное, быстрее?..
Но ... у меня в локальной сети (общежитие) сокеты закрыты.
Кроме того, выход из сети через прокси (прямое соединения от сервера ко мне установить нельзя) и уверен, что такие ограничения не только у меня бывают.
Чтобы оставить универсальность программы - предпочитаю делать так, как есть


2. Работа с файлами - очень долго.
Как можно реализовать хранение и доступ к данным быстрее?
Писать в БД? Если будет много временных меток (вроди как пока что не предпологается) - было бы быстрее искать.
Иначе - всё равно ведь в конечном итоге из файлов читается, не так ли?

Что мне приходит в голову - поставить на сервере JBOSS, и запихнуть туда Session EJB, для каждого пользователя создаётся своё Бин и лежит в памяти (быстродоступно) до конца работы.

Но ... хотелось бы, относительной, универсальности кода.
А далеко не на всякий сервер можно выложить Бины ...
Не говоря уже о бесплатных серверах (а о чём иначе может быть речь при амматорском проэкте студента?..).

Хостинг с поддержкой сервлетов и jsp у меня есть.
Но, может ли это как-то помочь?

И последнее.
Графика это, конечно же, хорошо.
Но ... в планах было бы туда ещё звук прикрутить ...
Stream ....
Писать это в файлы или в БД - глупо ... наверное ...
Создавать файлы у пользователя в Апплете, аплоадить их на сервер, а потом отдавать по мере надобности?
Не представляю.

В общем.
Если у кого-то есть идеи/знания по этому поводу - буду рад их услышать!

Deady
13.06.2005, 12:43
1. объясни пожалуйста, что такое "сокет" в твоем понимании.
если будет работа с БД, то можно из апплета сразу к БД коннектиться (хотя так не рекомендуется делать)

2. сравнивать файлы и БД не вижу смысла. люди не для того БД годами придумывали, чтоб потом их заменяли на работу с файлами

если есть JBoss, то автоматически есть JSP и пр. смысла писать на php не вижу вообще.

сдается мне, в том примере доски не отрезки используются. там имхо матрица точек, она же и передается.

Deady
13.06.2005, 12:55
нет, я наврал....
там есть текущая точка, от нее все время строится отрезок к текущему положению курсора. если быстро поволить, то видно, что иногда вместо кривых отрезки получаются.
я такое в школе когда-то писал для интереса.
нужно в отдельном потоке время от времени передавать на сервер или последовательности отрезков, или можно находить изменившуюся часть рисунка и передавать ее в виде матрицы.
кстати, если правой кнопкой щелкнуть - все стирается. из этого логично предположить, что серверная часть просто хранит текущий холст в памяти (например в виде bean). в принципе быстро, но потом неудобно будет реализовывать функцию закрытых групп (т.е. рисовать могут только определенные люди).
обмен можно делать например с помощью ObjectOutputStream.

Oscar
13.06.2005, 16:00
Deady,
1. Сокет - канал связи с хостом по заданному ПОРТУ.
Пересылка пакетов из локальной сети во внешнюю разрешена (кажется) только по 80-му порту.
Хотя ... связь с БД строкой:
"jdbc:oracle:thin:@srvmatthes4.informatik.tu-muenchen.de:1521:dbprak"
удаётся натроить.

Почему не рекмендуется коннектится к БД из апплета?..

2. БД удобна для больших обьёмов информации и поиска в ней.
Если же информации не много и получать её нужно всю, то файлы должны быстрее работать,
так мне кажется.

3. JBOSSа нету ... Есть бесплатный хостинг лишь с Tomcat (вот там JSP и Servlet написать можно).

4. "смысла писать на php не вижу вообще"
Если на сервере нужно только записать в файл (БД) какая разница, делать это через Сервлет или через PHP?
Сервлеты разве будут быстрее?
Почему php - потому что в этом случае серверную часть можно будет поставить на любой сервер, поддерживающий PHP
(а таких больше, чем с поддержкой Java).

5. По DRAGG мышки рисуется отрезок от старого положения мышки до нового.
Причём, для получения данные, которые будут пересылаться на сервер (для уменьшения обьёма) отрезки складываются в длинные линии.
(Алгоритм преобразования отрезков в линии не идеальный, а потому бывают промежутки, улучшить это я постараюсь сам).

6. Данные на сервере (http://home.informatik.tu-muenchen.de/~skrypnyo/painter/data.dat) хранятся сейчас в формате:



...
MICROTIMESTAMP 0.87798600 1118652480
60 138 60 137
67 110 67 108
67 110 67 109
67 108 69 106
69 105 71 103
69 105 70 104
71 103 72 102
...


Строка = Метка времени или линия (x1, y1, x2, y2)


7.

нужно в отдельном потоке время от времени передавать на сервер или последовательности отрезков, или можно находить изменившуюся часть рисунка и передавать ее в виде матрицы.

В отдельном потоке - это хорошая идея, спасибо!
Писать данные на сервер НЕ по концу драга, а по опрашиванию новых данных!
Уменьшится число обращений к серверу!

Что касается "изменившеюся часть рисунка .. в виде матрицы"
то .. передать пару линий (4 int) быстрее, чем передавать матрицу (прямоугольник X*X int) где основная часть будет белой!


-----

Основной вопрос:
Где и как хранить данные на сервере, чтобы доступ к ним был очень быстрым ?


"обмен можно делать например с помощью ObjectOutputStream"

Чем это лучше того, что я пишу Vector.add(int[4]) ?
Ведь всё равно эти данные потом записываются в POST при отправке на сервер.


"серверная часть просто хранит текущий холст в памяти (например в виде bean)"

Серверная часть, как я уже сказал в пункте 6 хранит не холст, а 4-точки для линий.
Хранить холст в памяти пользователя - он и так сохранён там.

На сервере - как сделат, чтобы обьект существовал постоянно?

Да, JBOSS и EJB это могут (насколько я понимаю), но у меня нет сервера с JBOSS.

Ведь вся проблема в том, что мне нужно хранить данные на сервере и отдавать их всем пользователям!

Немного обьясню, может я не понятно написал, суть всего этого дела:
5 (много) пользователей находятся на одной странице и одновременно рисуют на одном экране!

Kolinus
13.06.2005, 17:03
На самом деле вопрос довольно сложный потому как:
если база хорошая - то быстрее будеть база
если база не лчень шустрая, то возможно что и файл.
Опять же пхп скорее шустрее отработает с файлами - просто вызовет системную функцию
Хотя винчестер - самое узкое место практически в любом компе.
Если хочешь знать точно насчет своего случая - то самый надежный способ проверить.
только на самм деле зачем если у тебя сервер с явой, то писать на пхп.
Напиши сервлетик - пусть он и кидает в БД.
Ява использует байт код а пхп - чисто интерпретируемый язык посему ява должна шустрее отработать
Плюс если хочешь быстрее - то лучше через сокеты данные толкать.

Kolinus
13.06.2005, 17:04
да база у тя судя по всему оракл так что кидай все в базу и не парься
звук потом подцепишь - просто в bfile будешь складывать и все
а унифицированное хранение - всегда рулить

Oscar
13.06.2005, 17:23
Kolinus,
спасибо за ответ!

Прочитал статью The Servlet Life Cycle (http://www.unix.org.ua/orelly/java-ent/servlet/ch03_01.htm).
Был ужжасно рад :D что сервлет есть одна инстанция в памяти!
Так что файлы и БД отпадают!
Буду хранить в переменных в оперативке, о чём я так мечтал ))


Deady,
"обмен можно делать например с помощью ObjectOutputStream"
Прошу прощения, я не правильно подумал, как оно работает.
Теперь понял, спасибо!
Это, опять же таки, то, что мне нужно!

поставил кофе, пошел за сигаретами ;)

Deady
14.06.2005, 11:48
по поводу: что передавать.
передача отрезкав и матрицы - это как векторная и спрайтовая графика. а опыт подсказывает, что спрайты работают быстрее.
пример:
пусть у тебя отложенная передача данных (как я и посоветовал - передавать только по запросу). я нарисую в маленьком квадрате (10*10) сотню отрезков. на отрезок - 4 байта*100 = 400 байт.
матрица: 10*10 = 100 байт, а с учетом того, что всего 2 цвета (ч/б) = то 100/8 = 13 байт.

Deady
14.06.2005, 11:50
почему лучше java+java чем java+php:
ну потому что во втором случае ты сможешь передавать данные только в рамках http запроса, не будет доступен тот же ObjectOutputStream.
и вообще, ты же не станешь ставить двигло от бмв на ауди...

Deady
14.06.2005, 11:52
по поводу "что почитать".
Core Servlets And JSP - там все хорошо описано. в частности есть глава про взаимодействие сервлетов и апплетов.

Oscar
14.06.2005, 16:39
Deady,

1.
по поводу: что передавать.
аргументацию на примере не понял
(a) почему во втором случае "делить"?
(b) в будущем планируется НЕ ОДИН цвет

интуитивно, как бы да!
много линий, накладываются, ок, но!
Зачем пользователю накладывать одну линию на другую?

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

Другой вопрос: Как передавать спрайтовую графику на сервер?
Раз в секунду скидывать всю Графику апплета?
Накладывать на сервере Графики всех пользователей на одну и рассылать обратно?

Как я себе представляю - это будут рывки, при плохой связи так точно.

Если же я передаю линии:
Да, траффика может будет в конечном итоге и больше (хотя, это вовсе не обязательно должно быть!), но каждый раз будет пересылатся всего ОДНА линия! (4*int + цвет).
Таким образом это будет более равномерно.

И, кроме того, никто же не будет постоянно рисовать там одно на другом! Для того правая кнопка мышки и введена, чтобы стереть!


В общем пока ещё так и не определился.

2.

почему лучше java+java чем java+php:
ну потому что во втором случае ты сможешь передавать данные только в рамках http запроса, не будет доступен тот же ObjectOutputStream.

Да, хорошо. С этим я согласен.
ObjectOutputStream (ObjectInputStream) я уже настроил.
Работает оно тут: Applet-Servlet.html (http://www.myjavaserver.com/~olegskr/AppletServlet.html)
, а коды всех классов можно видеть в корневом каталоге:
http://www.myjavaserver.com/~olegskr/

К сожалению, установить связь между апплетом и сервлетом через Сокеты не удалось (Access Denied, Permission, ...)


и вообще, ты же не станешь ставить двигло от бмв на ауди...
Я бы рассматривал это иначе.
Если бы не было явного преимущества в In(Out)putStream я бы делал серверную часть на php.
Если общение идёт исключительно "plain text" через HTTP - то какая разница, на чём сервер, а на чём клиент?
А, как я уже говорил, серверов с поддержкой PHP намного больше (а бесплатный с поддержко Java я вообще только один знаю).

Если нужно будет поделиться с кем-то кодом - php (или asp, perl, cgi) проще найти. И все они смогли бы работать с файлами.

Ну да ладно, теперь это уже не актуально, потому как со Стрим я разобрался, и мне очень понравилось! ))

3.

по поводу "что почитать".
Core Servlets And JSP - там все хорошо описано

Спасибо, но та статья ("The Servlet Life Cycle"), на которую я ссылался в прошлом мессадже,
оказалась главой из книги О'Рейлли "Java™ Servlet Programming", чему я очень доволен.
Сейчас её пролистываю по мере необходимости.


---

Опять возник вопрос: в чём хранить?
Все дело в том, что на myjavaserver.com классы довольно таки часто выгружают из памяти (минут 5-10 неактивности).
А потому, чтобы сохранить состояние между сеансами нужно выгружать содержание (которое хранится в переменных обьекта Сервлет, который, как оказалось ранее, имеет, грубо говоря, всего одну инстанцию) на жесткий диск.

Пример такой выгрузки тут: InitDestroyCounter (http://www.myjavaserver.com/servlet/olegskr.InitDestroyCounter)
код доступен в корне (см. выше).

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


И ещё один вопрос: Как идентифицировать пользователя?
Servlet(Remote IP) (http://www.myjavaserver.com/servlet/olegskr.RemoteIP)
Applet(Local IP) (http://www.myjavaserver.com/~olegskr/LocalIP.html)

У меня :
RemoteIP = IP Прокси-Сервера локальной сети
LocalIP = 127.0.0.1

Если я захочу "порисовать" вместе с человеком из моей сети - будут проблемы.

(Зачем мне нужно IP? Список пользователей, состояние online).

Есть ли возможность как-то получить что-то типа:
X-Forwarded-From (или как там его) ?

Тогда я буду идентифицировать по (RemoteIP+LocalIP).

В сервлете RemoteIP я вывожу также Header, но там нету необходмой мне информации.
Вообще, это возможно то, что я хочу?

Oscar
15.06.2005, 00:24
Другой вопрос: Как передавать спрайтовую графику на сервер?

Создал я, значиться, в апплете картинку:


Image offscreen = createImage(getWidth(), getHeight());
Graphics offgraphics = offscreen.getGraphics();

Переменная offscreen в результате оказалась класса sun.awt.image.OffScreenImage :?

Был очень удивлён, открыв для себя, что оно знает какой-то пакет sun

Апплет сам по себе отрабатывает на "ура"!
Рисую линию по MouseDragged в этот самый offgraphics,
после чего делаю repaint изменённого прямоугольника.

В методе paint делаю:

public void paint(Graphics graphics) {
graphics.drawImage(offscreen, 0, 0, null);
}

Всё, как по нотам!
Моментально рисует, обновляет маленькую область шустро.
Если свернуть/развернуть окно - аккуратненько прорисовывает всё заново.

Ок, решил передать это на сервер.
И шо вы думаете?...


java.io.NotSerializableException: sun.awt.image.OffScreenImage
:(

Попытался создать класс

public class PainterImage extends Image implements Serializable

Что как писать - не понял, понял, что гемороя будет много.
Кроме того, в апплете я ведь всё равно получу этот самый SUNовский OffScreenImage, который привести к моему PainterImage вряд ли удасться.
Что делать? Полностью переписывать свой PainterImage по типу OffScreenImage и добавлять в него сериализацию! Нет уж, увольте ...

Как результат всех этих изощрений - решил вернуться к своим линиям .. Буду передавать Vector(int[4]), который таки есть serializable.

Если кто-то знает как можно это делать иначе - буду рад услышать умную мысль.