2009-11-14 19 views
14

Jak zaimplementować serwer echa połączeń 10k w Clojure?Programowanie serwera z Clojure

clojure.contrib.server-socket nie jest odpowiedzią, ponieważ tworzy nowy wątek systemu operacyjnego dla każdego połączenia.

+2

Czy odwołujesz się do problemu c10k? http://www.kegel.com/c10k.html –

+0

Czytam to, tak, i jestem ciekawa, w jaki sposób zostanie on zaimplementowany w tym interesującym języku. Zauważ, że clojure bardzo często reklamuje swoje możliwości współbieżności. – Roskoto

Odpowiedz

29

Wspaniałą rzeczą w Clojure jest to, że posiadasz wszystkie te wspaniałe biblioteki dla JVM, takie jak netty, które są wysoce zoptymalizowane, konfigurowalne i dobrze przemyślane. Coś takiego powinno ci pomóc:

(ns netty 
    (:gen-class) 
    (:import 
    [java.net InetSocketAddress] 
    [java.util.concurrent Executors] 
    [org.jboss.netty.bootstrap ServerBootstrap] 
    [org.jboss.netty.channel Channels ChannelPipelineFactory 
           SimpleChannelHandler] 
    [org.jboss.netty.channel.socket.nio NioServerSocketChannelFactory] 
    [org.jboss.netty.buffer ChannelBuffers])) 

(declare make-handler) 

(defn start 
    "Start a Netty server. Returns the pipeline." 
    [port handler] 
    (let [channel-factory (NioServerSocketChannelFactory. 
          (Executors/newCachedThreadPool) 
          (Executors/newCachedThreadPool)) 
     bootstrap (ServerBootstrap. channel-factory) 
     pipeline (.getPipeline bootstrap)] 
    (.addLast pipeline "handler" (make-handler)) 
    (.setOption bootstrap "child.tcpNoDelay", true) 
    (.setOption bootstrap "child.keepAlive", true) 
    (.bind bootstrap (InetSocketAddress. port)) 
    pipeline)) 

(defn make-handler 
    "Returns a Netty handler." 
    [] 
    (proxy [SimpleChannelHandler] [] 
    (channelConnected [ctx e] 
     (let [c (.getChannel e)] 
     (println "Connected:" c))) 

    (channelDisconnected [ctx e] 
     (let [c (.getChannel e)] 
     (println "Disconnected:" c))) 

    (messageReceived [ctx e] 
     (let [c (.getChannel e) 
      cb (.getMessage e) 
      msg (.toString cb "UTF-8")] 
     (println "Message:" msg "from" c))) 

    (exceptionCaught 
     [ctx e] 
     (let [throwable (.getCause e)] 
     (println "@exceptionCaught" throwable)) 
     (-> e .getChannel .close)))) 
+3

Dzięki! Stawiam prosty projekt leiningen do tego tutaj: https://github.com/cymen/clojure-netty – Cymen

+1

Jak wysłać wiadomość na ten serwer? – vemv

+1

@vemv Zaktualizowałem repozytorium, aby używał projektu github do korzystania z publicznej sieci i dodałem przykład, jak wysłać wiadomość do serwera. – Cymen