A 77 lines echo server in clojure
2023-03-14 22:28:50 时间
写着玩的,不使用任何网络框架从头构建的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 }))
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 }))
文章转自庄周梦蝶 ,原文发布时间 2011-01-15
相关文章
- 干货分享--DW软件 Dreamweaver(Dw) 2021安装 DW2022苹果稳定版
- 2023-02-16:两种颜色的球,蓝色和红色,都按1~n编号,共计2n个, 为方便放在一个数组中,红球编号取负,篮球不变,并打乱顺序, 要求同一种颜色的球按编
- 干货分享--AU软件下载 Au 2021安装教程 au2022下载
- 一体化的管理平台=业务+研发?
- 【持续更新】Rstudio使用Note
- WordPress WP-Super-Cache 缓存插件 Nginx 规则
- 使用 Proxifier 加速 GitHub Copilot 服务
- GitLab 14 修改默认语言
- ChatGPT国内直接用,从注册到使用保姆级教程,亲测绝对有效!
- R语言DCC-GARCH模型对上证指数、印花税收入时间序列数据联动性预测可视化
- 用COPULA模型进行蒙特卡洛(MONTE CARLO)模拟和拟合股票收益数据分析|附代码数据
- 力扣3-无重复字符的最长子串
- 数据分享|R语言逐步回归、方差分析anova电影市场调查问卷数据可视化|附代码数据
- CleanMyMac更新最新版本V4.12.5功能使用教程
- 智慧工地火焰烟火识别检测系统
- 全球音频领域哪家强--盘点音频领域常用的python库
- chatgpt与游戏相结合提高游戏的丰富度与可玩性
- SAP UI5 应用的标准 Theme 和自定义 Theme 的加载讨论
- 分层次的电路设计方法
- Postgresql中return setof函数的使用方法与实例