Спустя почти год после опубликования последней статьи и обещания рассказать о реализации веб-сокетов я, наконец-то, волевым решением выделил время на столь приятное для меня и полезное для Вас занятие.
Эта статья открывает серию уроков, посвященных реализации такого невероятно полезного механизма как websocket средствами сервера GlassFish. В отличии от серии статей JavaEE здесь не будет сквозного примера у первых уроков. Далее по мере увеличения сложности и изученных возможностей возможно реализуем что-нибудь серьезное, чтобы объеденить в себе весь функционал технологии веб-сокетов.
Если Вы прочли все статьи серии JAVA EE и реализовали указанные там примеры, то далее можете приступать к изучению без замедления т.к. все необходимые для понимания уроков знания у Вас уже есть.
Поговорим о том зачем нужны эти самые websocket'ы.
Представим такую ситуацию: вам необходимо активно обмениваться с сервером некоторыми данными и на их основе формировать какие-то действия на клиентской стороне программы, причем вы подвязаны на события и данные, происходящие именно на сервере и вам нужно оперативно о них узнавать и что-то предпринимать. Вы не знаете когда и в каком виде произойдет событие на сервере, но узнать о нем и его результатах нужно максимально оперативно.
Например, сообщить клиенту о том, что ему пришло личное сообщение или уведомление, или закончилась длительная обработка пакета файлов, или это вовсе онлайн-игрушка и нужно постоянно получать данные о некторых событиях (вспышка справа, выстрел слева, солнце село).
Лично я представляю 3 варианта решения подобной задачи не прибегая к помощи технологии flash или java апплетов:
- Ajax. Постояный, рекурсивный или по таймеру опрос сервера на наличие изменений. Такой вариант для каждого запроса открывает новое соединение с сервером, что его нагружает. При "грамотном" подходе можно 3-мя посетителями положить сервер на лопатки и заставить его страдать. Оперативность получения информации о событии на сервере зависит от частоты опроса и удачи клиента. Мы не можем узнать о событии ровно в момент его происхождения, только в один из шагов опроса сервера.
- IFrame. Если Вы истинный Мсье и знаете толк в извращениях, то это же можно реализовать при помощи замудренных Ifram'ов. В общем IFrame - это
1только для истинных ценителей.
- WebSoked. Да, да, именно наш websoked. Сплошные плюсы: асинхронность, малая нагрузка на сервер, двустороний вызов событий передачи данных, что делает процесс получения данных максимально оперативным.
С приходом WebSoсked html перестал быть однонаправленным, теперь данные можно получать не только по инициативе клиента, но и по инициативе сервера.
В этой статье мы реализуем минимально возможный функционал веб-сокетов. Этакий легковесный аналог ajax., т.к. по сути клиент будет вызывать событие обмена данными, а не сервер. Однако этого функционала более чем достаточно для понимания работы веб-сокетов на сервере GlassFish.
Реализация серверной части. Слушатели и обработчики.
Итак, запускаем NetBeans, и создаем веб-приложение ws_lesson1.
Создаем класс websocked. В нем у нас и будет весь функционал сервера.
Теперь нам необходимо зарегистрировать слушателя websocked'a на сервере и указать адрес, по которому он будет находиться. Все это мы сделаем одной короткой строкой. Как? Да так же как и раньше, при помощи аннотаций!
Добавьте перед объявлением класса аннотацию: @ServerEndpoint("/websocket")
.
Этой аннотацией мы автоматически зарегистрировали этот класс в сервере как слушателя websoked. Параметром в аннотации мы указал url адрес, по которому слушатель будет принимать соединение относильно корневого адреса проекта (именно проекта, а не домена).
import javax.websocket.server.ServerEndpoint;
/**
*
* @author a.egorov
*/
@ServerEndpoint("/websocket")
public class websocket {}
IDE поможет добавить вам в импорт класс ServerEndPoint.
В теле класса необходимо реализовать функции событий: открытия соединения, закрытия соединения, получения сообщения и вылета ошибки.
@ServerEndpoint("/websocket")
public class websocket {
@OnOpen
public void eventOpen(){
System.out.println("Соединение установленно...");
}
@OnClose
public void eventClose(){
System.out.println("Соединение закрыто");
}
@OnMessage
public String EventMessage(String message){
System.out.println("Получено сообщение от клиента:"+message);
String reply="Ваше сообщение: "+message+" было полученно;";
return reply;
}
@OnError
public void eventError(Throwable t){
System.err.println("Error WebSocket");
}
}
Для привязки функций к событиям используются соотвествующие аннотации перед объявлением функций @OnOpen, @OnClose, @OnMessage, @OnError.
IDE предложит Вам добавить классы, соотвествующие аннотациям, не отказывайте ей (это же она, да? :) ) в этом удовольствие.
На открытие и закрытие соединения мы в этом примере только выводим информацию в консоль.
Событие OnMessage происходит при получении сообщения от клиента и возращает ответ клиенту. В нашем случае за это событие отвечает функция EventMessage.
На этом серверная часть закончена. Неожиданно правда? Минимум кода, максимум продуктивности.
Клиентская часть. Создание объекта WebSocked, подключение к серверу и обмен данными.
Откроем файл index.html и добавим туда 3 элемента: поля для ввода сообщения, кнопку отправки и поле логирования процессов.
<input type="text" id="message" />
<input value="Отправить" onclick="sendMessage();" type="button"/>
<hr/>
<textarea readonly="readonly" id="messages" rows="15" cols="60"></textarea>
На событие "нажатие кнопки отправки сообщения" привязали функцию sendMessage.
Далее пишем javascprit код и внимательно читаем комментарии:
<script type="text/javascript">
/*создаем объект WebSocked и указываем путь для подключения.
* Подключение произойдет сразу после создания компонента.
*/
var webSocket = new WebSocket("ws://localhost:9090/ws_lesson1/websocket");
var messages=document.getElementById("messages");
var message=document.getElementById("message");
//обработчик события открытия соединения с сервером
webSocket.onopen=function(message){
messages.value+="Соединение установлено \n";
};
//обработчик события закрытия соединения с сервером
webSocket.onclose=function(message){
messages.value+="Соединение закрыто \n";
}
//обработчик ошибки при работе с сокетом.
webSocket.onerror=function (message){
messages.value+="Произошла ошибка \n";
}
//обработчик нажатия кнопки отправки сообщения
function sendMessage(){
//отправляем сообщение на сервер
webSocket.send(message.value);
messages.value+="На сервер отправлено:>"+message.value+" \n";
message.value="";
}
//обработчик получения сообщения ОТ сервера.
webSocket.onmessage=function(message){
messages.value+="Получено сообщение от сервера: "+message.data+" \n";
}
</script>
Из комментария к коду можно понять все, что происходит в коде: создание компонента, объявление слушателей и обработка результатов.
Можно развертывать приложение, наслаждаться результатом.
Вот так легко и просто мы реализовали простейший механиз веб-сокетов. Его явный минус в том, что пока мы не можем выборочно рассылать сообщения клиентам, инициализированные сервером, только отвечать на запросы клиента. Однако даже такой вот механизм значительно экономит ресурсы сервера в отличии от ajax запросов.
В следующем уроке мы будем инициализировать сервером массовую рассылку сообщений различным пользователям.
1Важно. Комментарии на кириллице пока сервером воспринимаются болезненно, за выходные постараюсь исправить. Пока просьба писать в транслите или на английском.
1 Все налажено. Комментарии работают.
Комментарии
Spasibo za post! Nujnaya infa!
Пожалуйста! Пользуйтесь)
Картинок не видно: This image failed to load
Да, вы правы. Но они в контексте данной статьи и не столь важны. Вся соль в исходниках.
спасибо огромное за классные статьи, все бы так объясняли. Будет просьба-пишите больше, эти статьи прекрасны, все доходчиво и интересно.Очень бы хотелось прочитать статью про самые современные тенденции в java разработке- что сейчас применяют.
Спасибо за добрые отзывы о моей работе)
Когда я в свое время начинал знакомиться с JavaEE, я был неприятно удивлен тому что в рунете не было практически никакой информации о базовых принципах работы данной технологии. Все статьи что я находил, как правило, были оторваными друг от друга, там перечеслялись различные технологии, а о том как их заставить работать вместе и что из этого будет ни слова.
Все статьи были написаны профессионалами и для профессионалов, тем самым порог вхождения в данную технологию был не оправдано высок.
Учитывая все это, я понял что могу уменьшить ту брешь в рунете которую, почему, никто не хотел замечать. Я начал писать данные статьи с целью уменьшить порог и время вхождения новых программистов в JavaEE. Худо-бедно мне это удалось.
Статьи про передовые технологии в Java как раз относятся уже к разряду "профи статей", а еще так много не написано про более простые возможности.
У самого меня последние два года, по различным причинам, совсем нет времени на написание статей. В новый год успел написать статью про websocked и никак не могу дописать вторую часть хотя для нее уже все готово, нужно только оформить.
Однако, саму идею и сайт я не бросаю и все равно продолжу писать статьи :)
СПАСИБИЩЕ !!!
Спасибо, ждем продолжения !!!
Очень интересно почитать продолжение. Буду благодарен за статью.
На пороге 2018 год, а статей уже как 4 года нет)
Но не суть...
Многоуважаемый автор,
скачал проект, пытался своим скудным умом и кривыми ручками смастерить сам,
но появляется ошибка...
GlassFish Server 4.1, deploy, null, false
C:\Users\matyushenkois\Downloads\MyBlog-article9\MyBlog-article9\myblog\nbproject\build-impl.xml:1070: Модуль не развернут.
Подробные сведения приведены в протоколе сервера.
СБОРКА ЗАВЕРШЕНА СО СБОЕМ (общее время: 1 секунда)
как и что сделать не понимаю, ПРОШУ помочь.
сама строка:
1069 <target if="netbeans.home" name="-run-deploy-nb">
1070 <nbdeploy clientUrlPart="${client.urlPart}" debugmode="false" forceRedeploy="${forceRedeploy}"/>
1071 </target>