莊周夢蝶

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

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


          主站蜘蛛池模板: 建水县| 黄梅县| 满洲里市| 怀集县| 广安市| 阜阳市| 昭觉县| 曲周县| 同江市| 岳池县| 三原县| 孟连| 定襄县| 玉环县| 松江区| 长兴县| 青冈县| 丽水市| 英山县| 蓝山县| 宁化县| 通河县| 长乐市| 涟水县| 静安区| 卓资县| 金寨县| 华宁县| 洪雅县| 瑞安市| 且末县| 巩义市| 通许县| 民乐县| 调兵山市| 凯里市| 务川| 绥中县| 万安县| 辰溪县| 屯昌县|