Сегодня мы сделаем websocket-приложение с помощью одного только Tomcat и javascript на клиенте.
WebSocketServlet
Ключевым механизмом реализации websocket в Tomcat является класс org.apache.catalina.websocket.WebSocketServlet. Он расширяет обычный javax.servlet.http.HttpServlet а значит мы можем "мапить" его на url как это делаем с остальными своими сервлетами. Собственно сама наша реализация крайне проста:
import org.apache.catalina.websocket.StreamInbound; import org.apache.catalina.websocket.WebSocketServlet; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServletRequest; @WebServlet(name = "WsServlet", urlPatterns = {"/ws"}) public class WsServlet extends WebSocketServlet { @Override protected StreamInbound createWebSocketInbound(String s, HttpServletRequest httpServletRequest) { return new WsConnection(); } }
Мы тут реализуем метод, который возвращает объект, отвечающий за обслуживание websocket-соединения. Сам объект WsConnection выглядит так:
import org.apache.catalina.websocket.MessageInbound; import org.apache.catalina.websocket.WsOutbound; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.util.concurrent.ArrayBlockingQueue; public class WsConnection extends MessageInbound { public static ArrayBlockingQueue<WsOutbound> connections = new ArrayBlockingQueue<WsOutbound>(100); private WsOutbound outbound; @Override protected void onBinaryMessage(ByteBuffer byteBuffer) throws IOException { } @Override protected void onTextMessage(CharBuffer charBuffer) throws IOException { broadcast(charBuffer.toString()); } @Override protected void onOpen(WsOutbound outbound) { this.outbound = outbound; connections.add(outbound); } @Override protected void onClose(int status) { connections.remove(this.outbound); } private void broadcast(String message) { for (WsOutbound connection : connections) { try { CharBuffer buffer = CharBuffer.wrap(message); connection.writeTextMessage(buffer); } catch (IOException e) { e.printStackTrace(); } } } }
Тут мы расширяем MessageInbound, что позволяет нам переопределяя соответствующие методы обрабатывать события установления и обрыва соединения, получения сообщения и т.п. При подключении нового клиента мы добавляем его в синхронизированную очередь, при отключении - удаляем. При получении сообщения просто рассылаем его всем подключенным клиентам. Такой вот чатик :)
На клиентской стороне можно сделать много красивостей, но мы обойдёмся минимальным количеством кода. Только чтобы убедиться в работоспособности сервера.
<html> <head> <title></title> <script type="text/javascript"> var socket = new WebSocket("ws://mydomain.com:8080/ws"); socket.onopen = function() { alert("Соединение установлено."); }; socket.onclose = function(event) { if (event.wasClean) { alert('Соединение закрыто'); } else { alert('Обрыв соединения'); } alert('Код: ' + event.code + ' причина: ' + event.reason); }; socket.onmessage = function(event) { var logarea = document.getElementById("log"); logarea.value = event.data+"n"+logarea.value; }; socket.onerror = function(error) { alert("Ошибка " + error.message); }; function send() { var s = document.getElementById("in").value; socket.send(s); } </script> </head> <body> <input type="text" id="in" /><input type="button" onclick="send()" value="send" /> <br/> <textarea id="log" rows="8" cols="20">
Thank you for info!It's very useful.
ОтветитьУдалитьМожешь дать весь проект?
ОтветитьУдалитьджава 1.7 ?
Этот комментарий был удален администратором блога.
ОтветитьУдалитьЭтот комментарий был удален администратором блога.
УдалитьЕсть ли реализация клиента на java? Очень хотелось бы увидеть.
ОтветитьУдалитьhttps://github.com/TooTallNate/Java-WebSocket
Удалитьпроверено - клиент на андроиде великолепно работает чкрез wss
https://github.com/socketio/socket.io-client-java
УдалитьА как сделать то же самое на tomcat 8?
ОтветитьУдалитьОтличная почта. Можете ли вы написать сообщение о Webfirmframework?
ОтветитьУдалить