| Paste number 88598: | clojure-nio-da2 |
| Pasted by: | ossareh |
| When: | 3 months, 3 weeks ago |
| Share: | Tweet this! | http://paste.lisp.org/+1WD2 |
| Channel: | None |
| Paste contents: |
(ns net.michaelossareh.sockets.server.nio
(:use [clojure.contrib.except :only (throw-if)])
(:import java.io.IOException)
(:import java.net.InetSocketAddress)
(:import java.nio.ByteBuffer)
(:import java.nio.channels.ServerSocketChannel)
(:import java.nio.channels.SelectionKey)
(:import java.nio.channels.Selector)
(:import java.nio.channels.spi.SelectorProvider))
(defn make-socket-channel
"Creates a ServerSocketChannel"
[]
(ServerSocketChannel/open))
(defn bind-socket!
"Binds the socket to the given host and port"
[socket-channel host port]
(.bind (.socket socket-channel) (InetSocketAddress. host port)))
(defn close-socket!
"Disconnects the given socket"
[socket-channel]
(.close socket-channel))
(defn make-non-blocking!
"Sets the given socket to be in non-blocking mode"
[socket-channel]
(.configureBlocking socket-channel false))
(defn make-socket-selector
"Creates a Selector"
[]
(.openSelector (SelectorProvider/provider)))
(defn close-socket-selector!
"Closes the Selector"
[selector]
(.close selector))
(defn register-selector-to-socket!
"Configures the selector to event on the given type on the given socket"
[socket-channel selector selection-key-type]
(.register socket-channel selector selection-key-type))
(defn accept-connection
"Accepts the acceptable connection from the key and returns the SocketChannel for the client"
[selection-key]
(let [server-socket-channel (.channel selection-key)
client-socket-channel (.accept server-socket-channel)]
client-socket-channel))
(defn read-bytes!
"Reads the bytes from a key into a ByteBuffer, calls clear on the buffer supplied"
[key byte-buffer]
(let [socket-channel (.channel key)
_ (.clear byte-buffer)] ;; clears and returns self
;; read within a try block, clean up on exceptions
(try
(let [bytes-read (.read socket-channel byte-buffer)]
;; throw exception if read returns -1
(throw-if (= -1 bytes-read)
IOException )
byte-buffer) ;; return the byte buffer
;; in the case of an exception clean up
(catch IOException _ (do (println "5") (.close socket-channel)
(.cancel key))))))
(defn make-byte-buffer
"Create a byte buffer, size provided in k"
[buffer-size]
(ByteBuffer/allocateDirect (* buffer-size 1024)))
(defn recv
"Accepts and reads from new connections, bytes will be read and passed to the given reader function."
;; [selector byte-reader buffer-size]
;; (let [byte-buffer (ByteBuffer/allocateDirect (* buffer-size 1024))]
[selector byte-reader]
(let [byte-buffer (make-byte-buffer 8)] ;; should eventually be removed and replaced by arg
;; start recv loop
(loop [event-count (.select selector)
selected-key-set (.selectedKeys selector)]
(println (str "number of events: " (.size selected-key-set)))
;; process the keys
(doseq [key selected-key-set]
(println (str "is nil? " (nil? key)))
(cond
;; key may not be valid anymore;
(false? (.isValid key)) (println "not valid")
;; accept if key is acceptable
(true? (.isAcceptable key)) (do (println "accepting socket")
(let [client-socket-channel (accept-connection key)]
(println (str "is nil? " (nil? client-socket-channel)))
(make-non-blocking! client-socket-channel)
(register-selector-to-socket! client-socket-channel selector SelectionKey/OP_READ)
(println "accepted socket")))
;; read 8k of bytes and feed to byte-reader
(true? (.isReadable key)) (do (println "reading")
(read-bytes! key byte-buffer)
(println byte-buffer)))
(.remove selected-key-set key))
;; recur
(recur (.select selector) (.selectedKeys selector)))))This paste has no annotations.