2012-06-06 51 views
6

我想通過clojure使用netty。我能夠啓動服務器,但是,它無法初始化接受的套接字。以下分別是錯誤消息和代碼。有誰知道什麼是/可能是錯誤的?我相信這個問題是(Channels/pipeline (server-handler))謝謝。Java Interop - Netty + Clojure

錯誤消息

#<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)))) 

回答

6

有三個問題與您的代碼

  1. Java的互操作與可變參數Channels.channel()方法。 您可以製作通道處理程序的矢量並將其包裝爲(into-array ChannelHandler ..)

  2. 您不能將字符串對象直接寫入Netty通道。 您必須首先將字符串寫入ChannelBuffer並寫入該緩衝區或使用StringCodecHandler。

  3. 寫入Netty通道是異步的,所以你不能立即關閉它。 您必須註冊未來的聽衆,並在完成後關閉頻道。

這裏是工作代碼。

(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)))) 

看一看Aleph(也一個Netty),它可以用來構建客戶端和服務器與漂亮的Clojure API許多不同的協議。

+0

感謝您的明確和詳細的解釋,這是非常有益的。當然,我計劃嘗試Aleph,但我想我會一箭雙鵰 - 在練習clojure的同時學習netty。 – Ari