Paste number 88598: clojure-nio-da2

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:
Raw Source | XML | Display As
(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.

Colorize as:
Show Line Numbers

Lisppaste pastes can be made by anyone at any time. Imagine a fearsomely comprehensive disclaimer of liability. Now fear, comprehensively.