莊周夢蝶

          生活、程序、未來
             :: 首頁 ::  ::  :: 聚合  :: 管理

          A 77 lines echo server in clojure

          Posted on 2011-01-15 22:56 dennis 閱讀(1899) 評論(0)  編輯  收藏 所屬分類: Clojure
              寫著玩的,不使用任何網絡框架從頭構建的echo server,總共77行。
           1 ;;Author:dennis (killme2008@gmail.com)
           2 (ns webee.network
           3    (:import (java.nio.channels Selector SocketChannel ServerSocketChannel SelectionKey)
           4             (java.net InetSocketAddress)
           5             (java.nio ByteBuffer)
           6             (java.io IOException)))
           7 
           8 (declare reactor process-keys accept-channel read-channel)
           9 
          10 (defn bind [^InetSocketAddress addr fcol]
          11   (let [selector (Selector/open)
          12         ssc      (ServerSocketChannel/open)
          13         ag  (agent selector)]
          14     (do
          15       (.configureBlocking ssc false)
          16       (.. ssc (socket) (bind addr 1000))
          17       (.register ssc selector SelectionKey/OP_ACCEPT)
          18       (send-off ag reactor fcol)
          19       ag)))
          20 
          21 (defn- reactor [^Selector selector fcol]
          22   (let [sel (. selector select 1000)]
          23     (if (> sel 0)
          24       (let [sks (. selector selectedKeys)]
          25         (do 
          26           (dorun (map (partial process-keys selector fcol) sks))
          27           (.clear sks))))
          28     (recur selector fcol)))
          29   
          30 (defn- process-keys [^Selector selector ^SelectionKey fcol sk]
          31   (try
          32     (cond 
          33       (.isAcceptable sk) (accept-channel sk  selector fcol)
          34       (.isReadable sk) (read-channel sk selector fcol)    
          35     )
          36     (catch Throwable e (.printStackTrace e))))
          37 
          38 (defn- accept-channel [^SelectionKey sk ^Selector selector fcol]
          39    (let [^ServerSocketChannel ssc (. sk channel)
          40          ^SocketChannel sc (. ssc accept)
          41          created-fn (:created fcol)]
          42      (do 
          43        (.configureBlocking sc false
          44        (.register sc selector SelectionKey/OP_READ)
          45        (if created-fn
          46          (created-fn sc)))))
          47 
          48 (defn- close-channel [^SelectionKey sk ^SocketChannel sc fcol]
          49   (let [closed-fn (:closed fcol)]
          50     (do 
          51        (.close sc)
          52        (.cancel sk)
          53        (if closed-fn 
          54          (closed-fn sc)))))
          55      
          56 (defn-  read-channel [^SelectionKey sk ^Selector selector fcol]
          57    (let [^SocketChannel sc (. sk channel)
          58          ^ByteBuffer buf (ByteBuffer/allocate 4096)
          59          read-fn (:read fcol)]
          60      (try
          61        (let [n (.read sc buf)]
          62          (if (< n 0)
          63              (close-channel sk sc fcol)
          64              (do (.flip buf)
          65                  (if read-fn
          66                    (read-fn sc buf)))))
          67        (catch IOException e
          68          (close-channel sk sc fcol)))))
          69 
          70 ;;Bind a tcp server to localhost at port 8080,you can telnet it.
          71 (def server
          72   (bind 
          73     (new InetSocketAddress 8080)
          74     {:read #(.write %1 %2)
          75      :created #(println "Accepted from" (.. % (socket) (getRemoteSocketAddress)))
          76      :closed  #(println "Disconnected from" (.. % (socket) (getRemoteSocketAddress)))
          77      }))


          主站蜘蛛池模板: 藁城市| 盘山县| 张北县| 竹溪县| 东莞市| 福建省| 吉隆县| 罗源县| 勐海县| 鄯善县| 高邮市| 临沭县| 申扎县| 合作市| 遵化市| 法库县| 通化市| 铜山县| 通辽市| 宝坻区| 如东县| 法库县| 昭苏县| 筠连县| 广汉市| 金山区| 盐山县| 郁南县| 焦作市| 金秀| 谷城县| 固镇县| 武鸣县| 突泉县| 南阳市| 吴忠市| 石楼县| 武夷山市| 韩城市| 商南县| 高雄县|