2012-03-08 2 views
1

Я работаю над небольшим прокси-сервером, который управляет связью подключений tcp-ip, которые запускаются в цикле выбора. Внешняя служба разговаривает с прокси-сервером через HTTP-сервер, встроенный в прокси-сервер, и эти запросы проходят весь путь до сокета, а затем возвращают ответ из этого сокета в ответ на исходный HTTP-запрос.Новое для Jetty - ожидание ответных данных с продолжением, исключение ASYNCSTARTED

У меня есть параллельные запросы (с уникальным идентификатором запроса), входящие на http-сервер, фактические сообщения в этих запросах застревают в очереди и передаются вместе с кучей соединений сокетов (определенный сокет будет соответствовать сообщению), а затем ответ сбрасывается в хеш. HTTP-запрос периодически проверяет хэш, пока не увидит ответ с соответствующим идентификатором запроса, или он истекает. Вот удивительная системная диаграмма, если это не имеет смысла.

Awesome system diagram

Я совершенно новый для использования Java для HTTP-нибудь, так что я решил использовать Jetty и создать простой запрос обработчик а-ля Hello World пример. Использование thread.sleep предотвращает одновременные запросы, и продолжения, насколько я могу судить, требуют срабатывания событий. Я бы предпочел, чтобы запросы проверяли хэш один раз в то время, а не на включение события подключения каждый раз, когда сокет помещает ответ в хеш, если события не загорелись идентификатором запроса или чем-то еще. Это не кажется практичным, если есть много трафика.

скалы:

  • Как сделать обработчик (или сервлет, если мне нужно идти так далеко) ждать для немного или периодически в то время как это данные становятся доступными без блокировки и все остальное?
  • Есть ли лучший способ сделать сообщение http осведомленным о данных, которые он должен вернуть в качестве ответа?
  • Этот дизайн плохой, и если да, то в чем альтернатива?

EDIT:

Вот мой первый удар в этой проблеме. Он отлично работает, когда HTTP-запрос указывает на идентификатор, который соответствует подключенному клиенту tcp. Если идентификатор не соответствует подключенному клиенту, причал идет бонкерс и попадает в цикл и снова и снова выдает следующее исключение. То, что я ожидаю, это запрос на тайм-аут, потому что он не может найти никаких сообщений в сборщике.

Mar 8, 2012 2:39:08 PM APIRequestHandler doPost 
INFO: json: {"state": "255", "m": "set", "id": "00:00:00:00:00:06", "rid": "84955228696f11e1aa04c42c033c8bd7", "sid": "XXXXX"} 
2012-03-08 14:39:08.526:WARN:oejs.ServletHandler:/ 
java.lang.IllegalStateException: ASYNCSTARTED,initial 
    at org.eclipse.jetty.server.AsyncContinuation.suspend(AsyncContinuation.java:365) 
    at org.eclipse.jetty.server.AsyncContinuation.suspend(AsyncContinuation.java:959) 
    at APIRequestHandler.doPost(APIRequestHandler.java:72) 
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:755) 
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:848) 
    at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:594) 
    at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:485) 
    at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:231) 
    at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1065) 
    at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:412) 
    at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:192) 
    at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:999) 
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:117) 
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:111) 
    at org.eclipse.jetty.server.Server.handle(Server.java:351) 
    at org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:454) 
    at org.eclipse.jetty.server.AbstractHttpConnection.content(AbstractHttpConnection.java:900) 
    at org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.content(AbstractHttpConnection.java:954) 
    at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:857) 
    at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:235) 
    at org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:76) 
    at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:609) 
    at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:45) 
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:599) 
    at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:534) 
    at java.lang.Thread.run(Thread.java:680) 

Servlet:

public void doPost(HttpServletRequest req, HttpServletResponse res) 
     throws java.io.IOException 
    { 
    String rid = req.getParameter("rid"); 
    String msg = req.getParameter("json"); 
    String id = req.getParameter("id"); 

    // Send to tcp-ip channel 
    APIMessage m = new APIMessage(); 
    m.rid = rid; 
    m.id = id; 
    m.json = msg + "\r\n"; 
    queue.add(m); 
    this.selector.wakeup(); 

    Continuation cc = ContinuationSupport.getContinuation(req); 

    res.setContentType("text/plain"); 
    res.getWriter().println("Request: "+rid+"\tstart:\t"+new Date()); 
    res.getWriter().flush(); 
    int elapsed = 0; 
    String responseStr = ""; 
    boolean timeoutHappened = true; 
    while(elapsed<this.timeout) // say 50 millis 
    { 
     if(collector.containsKey(rid)){ 
      responseStr = collector.get(rid); 
      collector.remove(rid); 
      timeoutHappened = false; 
      break; 
     } 
     cc.setTimeout(10); // sleep 10 millis 
     cc.suspend(); 
    } 

    if(!timeoutHappened) 
    { 
     logger.info("--->API http request found response in collector!"); 
     logger.info("Respose: "+responseStr); 
    } 
    else // timed out 
    { 
     logger.info("--->API http request timed out!"); 
    } 

    res.getWriter().println("Request: "+rid+"\tend:\t"+new Date()); 
    if(cc.isInitial()!=true) {cc.complete();} 
} 

ответ

0

Я хотел бы начать, глядя на то, что мы имеем в причале для проксирования уже.

http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/ProxyServlet.java

Если это не решает, что вы пытаетесь сделать, это, по крайней мере, чтобы вы начали.

Вы можете запустить этот сервлет легко внедренный с классом в тестах этого пакета:

http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AsyncProxyServer.java

удачи

+0

Спасибо.Я не думаю, что могу использовать стандартные события для тайм-аутов и подключаться в моем случае, поэтому я прибегаю к циклу. Он работает правильно, если входящий запрос не имеет клиента tcp, который соответствует переданному идентификатору. Я добавил код выше - не знаю, почему он должен потерпеть неудачу. – nflacco

+0

ваше использование продолжений отключено, вам нужно иметь проверку isInitial(), чтобы вы не выполняли одну и ту же логику более одного раза, посмотрите на сервлет-прокси-сервер для примера о том, как должен работать механизм продолжения. –

+0

Является ли причал не многораздельным из коробки? Оп, похоже, говорит, что одновременные запросы ставятся в очередь, а не выполняются асинхронно? – davidfrancis

Смежные вопросы