Reverse Ajax: Часть 3. Web-серверы и Socket.IO

Использование различных Web-контейнеров API и библиотек абстрагирования

В этом цикле статей говорится о том, как разработать событийно-управляемое Web-приложение с использованием методов Reverse Ajax. В первой части приведены различные способы реализации связи Reverse Ajax: опрос, составные вызовы и Comet, использующие ждущие опросы и потоки. В части 2 объясняется, как реализовать Reverse Ajax, используя WebSockets, и обсуждаются ограничения для Web-серверов с применением Comet и WebSockets. Эта статья о том, как использовать Comet и WebSockets в Web-приложениях для различных Web-контейнеров и API. А также о Socket.IO, библиотеке абстрагирования, которую можно применять в Web-приложениях на базе Reverse Ajax. Библиотеки абстрагирования, которые можно использовать прозрачно, скрывают всю сложность Comet и WebSockets.

Матье Карбу, Java Web-архитектор, Ovea

Фото Матье КарбуМатье Карбу (Mathieu Carbou), Java Web-архитектор и консультант компании Ovea, предоставляет услуги и разрабатывает решения. Он коммиттер и руководитель нескольких проектов по разработке ПО с открытым исходным кодом, докладчик и глава монреальской группы пользователей Java. Матье обладает богатым практическим опытом программирования и специализируется на разработке событийно-управляемых Web-программ для клиентских и серверных систем, а также на решениях для высокомасштабируемых Web-приложений, управляемых событиями и сообщениями. Познакомьтесь с его блогом.



16.08.2012

Введение

У современных пользователей востребованы быстрые, динамичные приложения, доступные через Интернет. В этом цикле статей показано, как разработать событийно-управляемое Web-приложение с использованием методов Reverse Ajax. Часть 1 знакомит читателя с методами Reverse Ajax - опросами, потоками, Comet и ждущим опросом. Из нее видно, что Comet с использованием ждущих HTTP-опросов ― это лучший способ надежной реализации Reverse Ajax, поскольку он поддерживается во всех современных браузерах. В части 2 показано, как реализовать Reverse Ajax с помощью WebSockets. Примеры кода помогают проиллюстрировать WebSockets, FlashSockets, ограничения на стороне сервера, сервисы, ограниченные одним запросом (request-scoped), и приостановку долгоживущих запросов.

В этой статье мы углубимся в детали использования Comet и WebSockets в Web-приложении для различных Web-контейнеров и API (Servlet 3.0 и Jetty Continuations). Вы научитесь прозрачно использовать Comet и WebSockets с помощью библиотек абстрагирования, таких как Socket.IO. Библиотека Socket.IO применяет методы обнаружения функций, чтобы решить, будет ли соединение установлено посредством WebSocket, ждущего опроса AJAX, Flash и т.п.

Загрузите исходный код примеров для этой статьи.

Предварительные требования

Чтобы извлечь максимальную пользу из этой статьи, в идеале нужно знать JavaScript и Java. Пример, создаваемый в этой статье, построен с помощью Google Guice - среды внедрения зависимостей, написанной на Java. Для работы с этой статьей требуется знакомство с идеями сред внедрения зависимостей, таких как Guice, Spring или Pico.

Для запуска примера из этой статьи также понадобится последняя версия Maven и JDK (см. раздел Ресурсы).


Серверные решения для Comet и WebSocket

В первой части мы рассказали, что для Comet (ждущий опрос или потоковая передача) требуется, чтобы сервер мог приостанавливать запрос и возобновлять или завершать его впоследствии, возможно, через длительное время. В части 2 говорится о том, как серверы должны использовать функции неблокирующего ввода/вывода для обработки большого количества соединений, а также о том, что для обслуживания запросов они используют только потоки (модель "поток на запрос"). Вы также узнали, что способ использования WebSocket зависит от сервера и не все серверы поддерживают WebSockets.

В этом разделе показано, как использовать Comet и WebSockets, если это возможно, на Web-серверах Jetty, Tomcat и Grizzly. Исходный код для этой статьи содержит Web-приложение для Jetty и Tomcat. В этом же разделе обсуждаются поддерживаемые API для следующих серверов приложений: JBoss, Glassfish и WebSphere.

Jetty

Jetty – это Web-сервер, поддерживающий спецификации Java Servlet 3.0, WebSockets и многие другие спецификации интеграции. Сервер Jetty:

  • отличается мощностью и гибкостью;
  • легко встраивается;
  • поддерживает виртуальные хосты, кластеризацию сеансов, а также множество функций, которые можно легко настроить с помощью Java- или XML-кода;
  • используется для в службеы хостинга Google App Engine.

Проектом Jetty управляет Eclipse Foundation.

Начиная с версии 6, в Jetty входит асинхронный API Jetty Continuations, который позволяет приостанавливать запросы и возобновлять их через некоторое время. В таблице 1 показана карта поддержки спецификаций и API для основных семейств версий Jetty.

Таблица 1. Версии и поддержка Jetty
ПоддерживаетJetty 6Jetty 7Jetty 8
Неблокирующий ввод/выводXXX
Servlet 2.5XXX
Servlet 3.0XX
Jetty Continuations (Comet)XXX
WebSocketsXX

Для реализации Reverse Ajax с помощью Comet можно использовать API Continuation из Jetty, как показано в листинге 1.

Листинг 1. API Jetty Continuation для Comet
// Приостановка запроса от метода сервлета (get, post, ...):

protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
        throws ServletException, IOException { 

Continuation continuation = ContinuationSupport.getContinuation(req); 
// дополнительное задание тайм-аута во избежание слишком долгого ожидания запроса  
continuation.setTimeout(0); 
// приостанавливает запрос 
continuation.suspend(); 
// затем сохраняет ссылку для будущего использования из другого потока 
continuations.offer(continuation); 

}

// Затем, из другого потока, который хочет отправить событие клиенту:

while (!continuations.isEmpty()) { 
    Continuation continuation = continuations.poll(); 
    HttpServletResponse response = 
        (HttpServletResponse) continuation.getServletResponse(); 
    // запись в ответ 
    continuation.complete(); 
}

Полное Web-приложение содержится в исходном коде, который прилагается к статье. Jetty Continuations находится в JAR-архиве. Этот JAR-файл нужно поместить в папку WEB-INF/lib Web-приложения, чтобы можно было использовать возможности Comet из Jetty. Jetty Continuations работает на Jetty 6, 7 и 8.

Начиная с Jetty 7 также имеется доступ к функции WebSockets. Чтобы получить доступ к API WebSocket из Jetty, поместите JAR-файл WebSocket из Jetty в папку WEB-INF/lib своего Web-приложения, как показано в листинге 2.

Листинг 2. API WebSocket из Jetty
// Реализация doWebSocketConnect и возврат реализации WebSocket: 

public final class ReverseAjaxServlet extends WebSocketServlet { 
    @Override 
    protected WebSocket doWebSocketConnect(HttpServletRequest request,
                                           String protocol) { 
        return [...] 
    } 
}

// Пример реализации WebSocket: 

class Endpoint implements WebSocket { 
    Outbound outbound; 
    public void onConnect(Outbound outbound) { 
        this.outbound = outbound;    
    } 
    public void onMessage(byte opcode, String data) { 
        outbound.sendMessage("Echo: " + data);
        if("close".equals(data)) 
             outbound.disconnect();
    } 
    public void onFragment(boolean more, byte opcode, 
                           byte[] data, int offset, int length) { 
    } 
    public void onMessage(byte opcode, byte[] data, 
                          int offset, int length) { 
        onMessage(opcode, new String(data, offset, length)); 
    } 
    public void onDisconnect() { 
        outbound = null; 
    } 
}

В папке jetty-websocket загружаемого исходного кода есть образец чата, который демонстрирует, как использовать API WebSocket из Jetty.

Tomcat

Tomcat, пожалуй, - самый популярный Web-сервер. Он применяется на протяжении многих лет и включен в качестве Web-контейнера в самые ранние версии сервера приложений JBoss. Tomcat используется и в качестве эталонной реализации спецификации сервлетов. В Servlet API 2.5 он исключен, так как люди стали искать альтернативы на основе неблокирующего ввода/вывода (такие как Jetty). В таблице 2 указаны поддерживаемые спецификации и API двух последних семейств версий Tomcat.

Таблица 2. Поддержка Tomcat
ПоддерживаетTomcat 6Tomcat 7
Неблокирующий ввод/выводXX
Servlet 2.5XX
Servlet 3.0X
Advanced I/O (Comet)XX
WebSockets

Как видно из таблицы 2, Tomcat не поддерживает WebSockets; однако в нем есть эквивалент Continuations из Jetty под названием Advanced I/O для поддержки Comet. Advanced I/O ― это скорее низкоуровневая оболочка для NIO, чем хороший API для облегчения использования Comet. Этот API плохо документирован, и примеров приложений, использующих его, немного. В листинге 3 показан пример сервлета для приостановки и возобновления запросов в Web-приложении чата. Полное Web-приложение находится в исходном коде, прилагаемом к этой статье.

Листинг 3. API Tomcat для Comet
public final class ChatServlet extends HttpServlet 
                               implements CometProcessor { 

    private final BlockingQueue<CometEvent> events = 
         new LinkedBlockingQueue<CometEvent>(); 

    public void event(CometEvent evt) 
        throws IOException, ServletException { 

        HttpServletRequest request = evt.getHttpServletRequest(); 
        String user = 
            (String) request.getSession().getAttribute("user"); 
        switch (evt.getEventType()) { 
            case BEGIN: { 
                if ("GET".equals(request.getMethod())) { 
                    evt.setTimeout(Integer.MAX_VALUE); 
                    events.offer(evt); 
                } else { 
                    String message = request.getParameter("message"); 
                    if ("/disconnect".equals(message)) { 
                        broadcast(user + " disconnected"); 
                        request.getSession().removeAttribute("user"); 
                        events.remove(evt); 
                    } else if (message != null) { 
                        broadcast("[" + user + "]" + message); 
                    } 
                    evt.close(); 
                } 
            } 
        } 
    } 

    void broadcast(String message) throws IOException { 
        Queue<CometEvent> q = new LinkedList<CometEvent>(); 
        events.drainTo(q); 
        while (!q.isEmpty()) { 
            CometEvent event = q.poll(); 
            HttpServletResponse resp = event.getHttpServletResponse();
            resp.setStatus(HttpServletResponse.SC_OK);
            resp.setContentType("text/html");
            resp.getWriter().write(message);
            event.close(); 
        } 
    } 
}

В Tomcat асинхронный сервлет должен реализовывать CometProcessor. Для асинхронных сервлетов Tomcat не вызывает стандартные HTTP-методы (doGet, doPost и т.п.). Вместо этого событие передается в метод event (CometdEvent). Когда запрос приходит впервые, пример проверяет, является ли он запросом GET, чтобы приостановить его. evt.close() не вызывается. Если это POST, то это означает, что пользователь отправил сообщение; в этом случае запрос пересылается другому CometEvent, и для завершения запроса post вызывается метод evt.close(). На стороне клиента программа рассылки выполняет все запросы ждущего опроса для завершения отправленного сообщения, а также немедленно направляет новый запрос ждущего опроса для приема следующих событий.

Grizzly и GlassFish

Grizzly – это не Web-контейнер, а скорее инфраструктура NIO, которая помогает разработчикам создавать масштабируемые приложения. Она разработана в рамках проекта GlassFish, но также может использоваться отдельно или как встроенный компонент. Grizzly содержит компоненты для работы в качестве HTTP/HTTPS сервера и для Bayeux Protocol, Servlet, HttpService OSGi, Comet и др. Grizzly поддерживает WebSockets и используется в Glassfish для обеспечения поддержки Comet и WebSocket.

Glassfish, сервер приложений Oracle, представляет собой эталонную реализацию спецификации J2EE 6.Glassfish – это полный комплекс, такой же, как WebSphere и JBoss, с использованием Grizzly для поддержки NIO, WebSocket и Comet. Модульная архитектура, основанная на OSGi, делает его чрезвычайно гибким с точки зрения замены компонентов. В таблице 3 показана поддержка Glassfish для Comet и WebSockets.

Таблица 3. Поддержка Glassfish
ПоддерживаетGlassfish 2Glassfish 3
Неблокирующий ввод/выводXX
Servlet 2.5XX
Servlet 3.0X
CometXX
WebSocketsX

Использовать Grizzly нетривиально, так как эта инфраструктура предназначена для встраивания или непосредственной работы из кода Java. Она широко применяется в качестве платформы для поддержки Comet и WebSockets, которую можно встроить в более крупное приложение, такое как Glassfish, которое обеспечивает развертывание Web-возможностей и спецификации Servlet API.

В разделе Ресурсы приведены ссылки на примеры WebSockets и Comet в Grizzly или GlassFish. Так как Glassfish использует Grizzly, примеры должны работать на обеих платформах. API WebSocket очень похож на API Jetty, но API Comet сложнее.

JBoss

Jboss - это сервер приложений, построенный на базе Tomcat. Он поддерживает Comet и NIO начиная с версии 5. Jboss 7 все еще находится в стадии разработки, но включен в таблицу 4.

Таблица 4. Поддержка Jboss
ПоддерживаетJboss 5Jboss 6Jboss 7
Неблокирующий ввод/выводXXX
Servlet 2.5XXX
Servlet 3.0XX
CometXXX
WebSockets

WebSphere

WebSphere – это сервер приложений IBM. Поддержка API Servlet 3 (со стандартизированным асинхронным API для Comet) появилась в версии WebSphere 8 (см. анонс в разделе Ресурсы).

Таблица 5. Поддержка WebSphere
ПоддерживаетWebSphere 8
Неблокирующий ввод/выводX
Servlet 2.5X
Servlet 3.0X
CometX
WebSockets

А как насчет общего API?

Каждый сервер предлагает свой собственный API для Comet и WebSocket. Легко догадаться, что написать переносимое Web-приложение – дело непростое. Спецификация Servlet 3.0 включает в себя дополнительные методы для приостановки и последующего возобновления запроса, что позволяет всем Web-контейнерам, поддерживающим спецификацию Servlet 3.0, поддерживать запросы ждущего опроса Comet.

Группа разработчиков Jetty предоставляет библиотеку Jetty Continuation, которая не зависит от контейнера Jetty. Библиотека Jetty Continuation достаточно умна, чтобы обнаружить присутствие контейнера или спецификации. При работе на сервере Jetty будет использоваться собственный API Jetty. При работе в контейнере, поддерживающем спецификацию Servlet 3.0, будет использоваться этот общий API. В противном случае используется немасштабируемая реализация.

Что касается WebSockets, то в Java еще нет соответствующего стандарта, и, следовательно, если вы хотите использовать в своем Web-приложении WebSockets, нужно брать API поставщика контейнера.

В таблице 6 приведена сводка технологий, поддерживаемых различными серверами.

Таблица 6. Технологии, поддерживаемые серверами
КонтейнерCometWebSocket
Jetty 6Jetty ContinuationsN/A
Jetty 7Servlet 3.0
Jetty Continuations
Native Jetty API
Jetty 8Servlet 3.0
Jetty Continuations
Native Jetty API
Tomcat 6Advanced I/ON/A
Tomcat 7Servlet 3.0
Advanced I/O
Jetty Continuations
N/A
Glassfish 2Native Grizzly APIN/A
Glassfish 3Servlet 3.0
Native Grizzly API
Jetty Continuations
Native Grizzly API
Jboss 5Native Jboss APIN/A
Jboss 6Servlet 3.0
Native Jboss API
Jetty Continuations
N/A
Jboss 7Servlet 3.0
Native Jboss API
Jetty Continuations
N/A
WebSphere 8Servlet 3.0
Jetty Continuations
N/A

Очевидного решения для WebSockets, за исключением API контейнера, не существует. Что касается Comet, то каждый контейнер, поддерживающий спецификацию Servlet 3.0, поддерживает и Comet. Преимущество Jetty Continuations в данном случае заключается в наличии поддержки Comet на всех этих контейнерах. Таким образом, некоторые библиотеки Reverse Ajax (которые рассматриваются в следующем разделе и в следующей статье этого цикла), в качестве своего серверного API используют Jetty Continuations.

API Jetty Continuation показан в примере Jetty для этой статьи. Спецификация Servlet 3.0 описана и используются в двух примерах Comet в первой части этой серии.


Библиотеки абстрагирования

Учитывая все основные API (Servlet 3.0 и Jetty Continuations), а также всю встроенную поддержку на стороне сервера и два основных способа выполнения Reverse Ajax на стороне клиента (Comet и WebSocket), написать свой собственный код JavaScript и Java для их объединения довольно трудно. Нужно также учесть тайм-ауты, прерывания связи, подтверждение, заявки, буферизацию и т.п.

Остальная часть этой статьи посвящена демонстрации Socket.IO в действии. В части 4 этого цикла рассматриваются Atmosphere и CometD. Все эти три библиотеки представляет собой ПО с открытым исходным кодом, и все они поддерживают Comet и WebSocket на многих серверах.

Socket.IO

Socket.IO - это клиентская библиотека JavaScript, которая обеспечивает единый API, подобный WebSocket, для подключиться к удаленному серверу, чтобы асинхронно передавать и принимать сообщения. Предоставляя общий API, Socket.IO поддерживает несколько транспортов: WebSocket, Flash Sockets, ждущий опрос, потоки, постоянные Iframes и опрос JSONP. Socket.IO определяет возможности браузера и пытается выбрать наиболее доступный транспорт. Библиотека Socket.IO совместима практически со всеми браузерами (в том числе старыми версиями, такими как IE 5.5), а также мобильными браузерами. Она также содержит такие функции, как такт, тайм-аут, отключение и обработка ошибок.

На сайте Socket.IO (см. раздел Ресурсы) подробно описано, как работает библиотека и какой браузер и метод Reverse Ajax используется. В принципе Socket.IO использует протокол связи, который позволяет клиентской библиотеке взаимодействовать с конечной точкой на стороне сервера, понимающего протокол Socket.IO. Socket.IO был разработан для Node JS, механизма JavaScript, используемого для создания более быстрых серверов. Многие проекты привнесли поддержку других языков, включая Java.

В листинге 4 приведен пример использования библиотеки JavaScript Socket.IO на стороне клиента. На веб-сайте Socket.IO есть документация и примеры.

Листинг 4. Использование клиентской библиотеки Socket.IO
var socket = new io.Socket(document.domain, { 
    resource: 'chat' 
}); 
socket.on('connect', function() { 
    // Socket.IO подсоединен
}); 
socket.on('disconnect', function(disconnectReason, errorMessage) { 
    // Socket.IO отсоединен
}); 
socket.on('message', function(mtype, data, error) { 
    // Сервер послал событие
});

// Теперь, когда обработчики определены, устанавливается связь:
socket.connect();

Чтобы использовать библиотеку Socket.IO JavaScript, нужна соответствующая часть Java - Socket.IO Java (см. раздел Ресурсы). Этот проект изначально создавался группой Apache Wave для добавления в Wave поддержки Reverse Ajax, когда еще не было WebSockets. Проект Socket.IO Java отделился и велся компанией Ovea (специализирующейся на событийной Web-разработке), однако затем компания от него отказались. Разработка серверной части поддержки клиентской библиотеки Socket.IO усложняется наличием нескольких транспортов. В части 4 этого цикла будет показано, что для достижения лучшей масштабируемости и поддержки браузера поддержка многих транспортов в клиентской библиотеке не обязательна, так как достаточно ждущего опроса и WebSockets. При отсутствии WebSockets Socket.IO все же был хорошим выбором.

Для приостановки и возобновления запросов Socket.IO Java использует API Jetty Continuation. Для поддержки WebSockets он использует собственный API Jetty WebSockets. Вы можете определить, какой сервер будет корректно работать с Web-приложением, использующим Socket.IO Java.

В листинге 5 приведен пример использования Socket.IO на сервере. Нужно определить расширение сервлета SocketIOServlet и реализовать метод, который возвращает своего рода представление конечной точки. Сам API очень похож на API WebSockets. Его преимущество заключается в том, что этот API используется на стороне сервера, независимо от транспорта, выбранного на стороне клиента. Socket.IO переводит все виды транспортов в один и тот же API на стороне сервера.

Листинг 5. Библиотека Socket.IO Java, используемая для примера чата - сервлет
public final class ChatServlet extends SocketIOServlet { 
    private final BlockingQueue<Endpoint> endpoints = 
        new LinkedBlockingQueue<Endpoint>(); 
 
    @Override 
    protected SocketIOInbound doSocketIOConnect
                                        (HttpServletRequest request) { 
        String user = 
                (String) request.getSession().getAttribute("user"); 
        return user == null ? null : new Endpoint(this, user, request); 
    } 
 
    void broadcast(String data) { 
        for (Endpoint endpoint : endpoints) { 
            endpoint.send(data); 
        } 
    } 
 
    void add(Endpoint endpoint) { 
        endpoints.offer(endpoint); 
    } 
 
    void remove(Endpoint endpoint) { 
        endpoints.remove(endpoint); 
    } 
}

В листинге 6 показано, как вернуть конечную точку.

Листинг 6. Использование библиотеки Socket.IO Java для примера чата - конечная точка
class Endpoint implements SocketIOInbound { 
 
    [...]
 
    private SocketIOOutbound outbound; 
 
    [...]

    @Override 
    public void onConnect(SocketIOOutbound outbound) { 
        this.outbound = outbound; 
        servlet.add(this); 
        servlet.broadcast(user + " connected"); 
    } 
 
    @Override 
    public void onDisconnect(DisconnectReason reason, 
                             String errorMessage) { 
        outbound = null; 
        request.getSession().removeAttribute("user"); 
        servlet.remove(this); 
        servlet.broadcast(user + " disconnected"); 
    } 
 
    @Override 
    public void onMessage(int messageType, String message) { 
        if ("/disconnect".equals(message)) { 
            outbound.close(); 
        } else { 
            servlet.broadcast("[" + user + "] " + message); 
        } 
    } 
 
    void send(String data) { 
        try { 
            if (outbound != null 
    && outbound.getConnectionState() == ConnectionState.CONNECTED) { 
                outbound.sendMessage(data); 
            } 
        } catch (IOException e) { 
            outbound.close(); 
        } 
    } 
 
}

Полный пример Socket.IO содержится в папке socketio исходного кода.


Заключение

Все Web-контейнеры поддерживают Comet, и почти все поддерживают WebSockets. Даже если спецификации ведут к нескольким разным реализациям, зависящим от платформы, все равно можно разработать Web-приложение с применением Comet с общими API (Servlet 3.0 или Jetty Continuations). Более того, применяя такие библиотеки, как Socket.IO, можно прозрачно использовать всю мощь Comet и WebSockets. Еще две библиотеки, Atmosphere и CometD, будут рассмотрены в следующей статье этого цикла. Все три библиотеки обеспечивают поддержку разных браузеров, открывают фантастические возможности для пользователей и поддерживают обработку ошибок, упрощенные API, тайм-ауты и возобновление соединений.


Загрузка

ОписаниеИмяРазмер
Исходный код примера для статьиreverse_ajaxpt3_source.zip21 КБ

Ресурсы

Научиться

Получить продукты и технологии

  • Jetty: Jetty, Web-сервер и контейнер javax.servlet с поддержкой WebSockets.
  • Документация Apache Tomcat Advanced I/O: полезные ссылки, руководство пользователя, справочник и инструкции по разработке для Apache Tomcat.
  • Grizzly NIO Framework: воспользуйтесь преимуществами API Java NIO.
  • Пример Comet для Grizzly: узнайте об изменениях, которые нужно внести в существующие приложения, прежде чем создавать новые с нуля.
  • Glassfish Application Server: основной пакет GlassFish Server Open Source Edition.
  • Socket.IO Java: получить оригинальный проект и самый последний вариант Ovea.
  • Apache Maven: инструмент для управления проектами разработки программного обеспечения.

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Web-архитектура, SOA и web-сервисы
ArticleID=830883
ArticleTitle=Reverse Ajax: Часть 3. Web-серверы и Socket.IO
publish-date=08162012