2012-06-06 17 views
6

Estoy tratando de usar netty a través de clojure. Puedo iniciar el servidor, sin embargo, no puede inicializar un socket aceptado. A continuación se muestran el mensaje de error y el código, respectivamente. ¿Alguien sabe qué es o podría estar mal? Creo que el problema es con (Channels/pipeline (server-handler)) Gracias.Java Interop - Netty + Clojure

mensaje de error

#<NioServerSocketChannel [id: 0x01c888d9, /0.0.0.0:843]> 
Jun 6, 2012 12:15:35 PM org.jboss.netty.channel.socket.nio.NioServerSocketPipelineSink 
WARNING: Failed to initialize an accepted socket. 
java.lang.IllegalArgumentException: No matching method found: pipeline 

project.clj

(defproject protocol "1.0.0-SNAPSHOT" 
    :description "Upload Protocol Server" 
    :dependencies [ 
    [org.clojure/clojure "1.2.1"] 
    [io.netty/netty "3.4.5.Final"]]) 

core.clj

(ns protocol.core 
    (:import (java.net InetSocketAddress) 
      (java.util.concurrent Executors) 
      (org.jboss.netty.bootstrap ServerBootstrap) 
      (org.jboss.netty.channel Channels ChannelPipelineFactory SimpleChannelHandler) 
      (org.jboss.netty.channel.socket.nio NioServerSocketChannelFactory) 
      (org.jboss.netty.buffer ChannelBuffers))) 

(def policy 
    "<content>Test</content>") 


(defn server-handler 
    "Returns netty handler." 
    [] 
    (proxy [SimpleChannelHandler] [] 
     (messageReceived [ctx e] 
      (let [ch (.getChannel e)] 
       (.write ch policy) 
       (.close ch))) 

     (channelConnected [ctx e] 
      (let [ch (.getChannel e)] 
       (.write ch policy) 
       (.close ch))) 

     (exceptionCaught [ctx e] 
      (let [ex (.getCause e)] 
       (println "Exception" ex) 
       (-> e .getChannel .close))))) 

(defn setup-pipeline 
    "Returns channel pipeline." 
    [] 
    (proxy [ChannelPipelineFactory] [] 
     (getPipeline [] 
      (Channels/pipeline (server-handler))))) 

(defn startup 
    "Starts netty server." 
    [port] 
    (let [channel-factory (NioServerSocketChannelFactory. (Executors/newCachedThreadPool) (Executors/newCachedThreadPool)) 
      bootstrap (ServerBootstrap. channel-factory)] 
     (.setPipelineFactory bootstrap (setup-pipeline)) 
     (.setOption bootstrap "child.tcpNoDelay" true) 
     (.setOption bootstrap "child.keepAlive" true) 
     (.bind bootstrap (InetSocketAddress. port)))) 

Respuesta

6

Hay tres problemas con su código

  1. interoperabilidad Java con el método vararg Channels.channel(). puede crear un vector de controladores de canal y ajustarlo con (into-array ChannelHandler ..)

  2. No puede escribir objetos String directamente en un canal Netty. primero tiene que escribir la cadena en un ChannelBuffer y escribir ese búfer o utilizar un StringCodecHandler.

  3. Escribir en el canal Netty es asíncrono, por lo que no puede cerrarlo inmediatamente. tiene que registrar un oyente futuro y cerrar el canal cuando esté listo.

Aquí está el código de trabajo.

(ns clj-netty.core 
    (:import (java.net InetSocketAddress) 
      (java.util.concurrent Executors) 
      (org.jboss.netty.bootstrap ServerBootstrap) 
      (org.jboss.netty.buffer ChannelBuffers) 
      (org.jboss.netty.channel Channels ChannelFutureListener ChannelHandler ChannelPipelineFactory SimpleChannelHandler) 
      (org.jboss.netty.channel.socket.nio NioServerSocketChannelFactory) 
      (org.jboss.netty.buffer ChannelBuffers))) 


(def policy 
    (ChannelBuffers/copiedBuffer 
    (.getBytes "<content>Test</content>"))) 


(defn server-handler 
    "Returns netty handler." 
    [] 
    (proxy [SimpleChannelHandler] [] 
    (messageReceived [ctx e] 
     (let [ch (.getChannel e)] 
     (.addListener 
      (.write ch policy) 
      (ChannelFutureListener/CLOSE)))) 

    (channelConnected [ctx e] 
     (let [ch (.getChannel e)] 
     (.addListener 
      (.write ch policy) 
      (ChannelFutureListener/CLOSE)))) 

    (exceptionCaught [ctx e] 
     (let [ex (.getCause e)] 
     (println "Exception" ex) 
     (-> e .getChannel .close))))) 

(defn setup-pipeline 
    "Returns channel pipeline." 
    [] 
    (proxy [ChannelPipelineFactory] [] 
    (getPipeline [] 
     (let [handler (server-handler)] 
     (Channels/pipeline (into-array ChannelHandler [handler])))))) 



(defn startup 
     "Starts netty server." 
     [port] 
     (let [channel-factory (NioServerSocketChannelFactory. (Executors/newCachedThreadPool) (Executors/newCachedThreadPool)) 
      bootstrap (ServerBootstrap. channel-factory)] 
     (.setPipelineFactory bootstrap (setup-pipeline)) 
     (.setOption bootstrap "child.tcpNoDelay" true) 
     (.setOption bootstrap "child.keepAlive" true) 
     (.bind bootstrap (InetSocketAddress. port)))) 

Tenga una mirada en Aleph (también utiliza Netty) que se utiliza para construir los clientes y servidores en muchos protocolos diferentes con buen API Clojure.

+0

Gracias por la explicación clara y detallada, fue muy útil. Ciertamente, planeo probar a Aleph, pero pensé que obtendría dos pájaros de un tiro: aprenderemos netty mientras practicamos clojure. – Ari