The code shown below is a try to write a simple tcp proxy using aleph.
Accessing http://localhost:local-port, the remote page http://remote-host:remote-port
should be fetched.
It works in principle, but when closing the connection, Java
exceptions arise like:
Apr 10, 2012 10:09:04 PM sun.reflect.NativeMethodAccessorImpl invoke0
WARNING: Unhandled exception in pipeline.
java.nio.channels.ClosedChannelException
at
org.jboss.netty.channel.socket.nio.AbstractNioWorker.cleanUpWriteBuffer(AbstractNioWorker.java:
674)
at
org.jboss.netty.channel.socket.nio.AbstractNioWorker.close(AbstractNioWorker.java:
622)
at
org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:101)
at
org.jboss.netty.channel.socket.nio.AbstractNioWorker.processSelectedKeys(AbstractNioWorker.java:
3
Can it be explained why these exceptions appear and how to avoid them?
FILE project.clj :
(defproject tcpProxyExample "1.0.0-SNAPSHOT"
:description "tcpProxyExample description"
:main tcpProxyExample.core
:dependencies
[
[org.clojure/clojure "1.3.0"]
[aleph "0.2.1-alpha2-SNAPSHOT"]
[gloss "0.2.1-alpha2-SNAPSHOT"]
[prxml "1.3.0"]
[io.netty/netty "3.4.0.Alpha2"]
]
:resources-path "src/main/resources:/opt/java1.6/jdk/lib/tools.jar"
)
FILE src/tcpProxyExample/core.clj
(ns tcpProxyExample.core)
(require 'aleph.tcp)
(require 'lamina.core)
(def local-port (atom 10080))
(def remote-host (atom "
www.cmyip.com"))
(def remote-port (atom 80))
(def msg-server-to-client (atom nil))
(def msg-client-to-server (atom nil))
(gloss.core/defcodec codec-gloss-byte :byte)
(defn vector-itoa-to-string
[vec]
"vector-itoa-to-string: [117 105 117 105 10] -> \"uiui\n\""
(apply str (map #(char %) vec))
)
(defn tcp-client-receiver [byt channel-of-server]
(println "+++ tcp-client-receiver [start]: (lamina.core/closed?
channel-of-server) -> " (lamina.core/closed? channel-of-server))
(let [
str (vector-itoa-to-string (
gloss.io/decode-all codec-gloss-
byte byt))
]
(reset! msg-client-to-server str)
(println "tcp-client-receiver: read: " msg-client-to-server)
;;
;; msg nur dann weiterleiten, wenn nicht nil
(if @msg-client-to-server (if-not (lamina.core/closed? channel-of-
server) (lamina.core/enqueue channel-of-server (
gloss.io/encode-all
codec-gloss-byte @msg-client-to-server))))
) ; let
)
(defn tcp-server-receiver [byt channel-of-client]
(println "+++ tcp-server-receiver [start]: (lamina.core/closed?
channel-of-client) -> " (lamina.core/closed? channel-of-client))
(let [
str (vector-itoa-to-string (
gloss.io/decode-all codec-gloss-
byte byt))
]
(reset! msg-server-to-client str)
(println "tcp-server-receiver: read: " msg-server-to-client)
;;
;; msg nur dann weiterleiten, wenn nicht nil
(if @msg-server-to-client (if-not (lamina.core/closed? channel-of-
client) (lamina.core/enqueue channel-of-client (
gloss.io/encode-all
codec-gloss-byte @msg-server-to-client))))
) ; let
)
;; Handler wird einmalig aufgerufen, wenn die Client/Server Verbindung
in Betrieb geht.
(defn tcp-server-handler [channel-from-arg connection-options]
(let [
channel-of-server channel-from-arg
channel-of-client (lamina.core/wait-for-result (aleph.tcp/tcp-
client {:host @remote-host :port @remote-port }) 1000)
]
(println "tcp-server-handler/channel-from-arg: " channel-from-arg)
(println "tcp-server-handler/channel-of-server: " channel-of-server)
(println "tcp-server-handler/channel-of-client: " channel-of-client)
(lamina.core/receive-all channel-of-client #(tcp-client-receiver %
channel-of-server))
(lamina.core/on-drained channel-of-client #(println "+++ on-drained
called for channel-of-client!"))
(lamina.core/on-closed channel-of-client #(println "+++ on-closed
called for channel-of-client!"))
;;
;; // hier werden vom externen Client gesendete Messages empfangen
(lamina.core/receive-all channel-of-server #(tcp-server-receiver %
channel-of-client))
(println (str "CONNECTION-OPTIONS" connection-options))
(lamina.core/on-drained channel-of-server #(println "+++ on-drained
called for channel-of-server!"))
(lamina.core/on-closed channel-of-server #(println "+++ on-closed
called for channel-of-server!"))
) ; (let
) ; tcp-server-handler
(defn -main [& args]
(aleph.tcp/start-tcp-server tcp-server-handler {:port @local-port })
) ; main