Статьи

Clojure: веб-сокет Введение

Веб-сокеты могут показаться пугающими, но если вы используете Clojure и jQuery, это на самом деле довольно просто.

Первое, что вам нужно сделать, это захватить сервер с поддержкой WebSocket. Jetty — неплохой вариант, но (недавно выпущенный Джо Уолнесом) webbit был самым быстрым выбором для начала работы.

Вы, вероятно, захотите:

git clone https://github.com/joewalnes/webbit.git
cd webbit
make jar

В этот момент у вас должны быть каталоги build и lib в вашем каталоге webbit. Вам нужно скопировать webbit / build / webbit.jar и webbit / lib / netty-3.2.3.Final.jar в новый каталог, в котором вы собираетесь создать приложение Web Socket. Вы также можете создать пустой server.clj и index.html. Теперь у вас должен быть каталог, который выглядит примерно так:

-rw-r--r--  1 jfields  jfields     674 Feb  7 08:58 index.html
-rw-r--r-- 1 jfields jfields 786229 Feb 6 10:49 netty-3.2.3.Final.jar
-rw-r--r-- 1 jfields jfields 693 Feb 7 08:58 server.clj
-rw-r--r-- 1 jfields jfields 59616 Feb 6 10:49 webbit.jar

Далее мы запустим веббит с помощью Clojure. README WebBit дает нам пример Java, который легко конвертируется. Следующий код запускает сервер и печатает его аргументы при открытии, закрытии или отправке веб-сокета.

(ns server
(:require [clojure.contrib.json :as json]
[clojure.string :as s])
(:import [webbit WebServer WebServers WebSocketHandler]
[webbit.handler StaticFileHandler]))

(doto (WebServers/createWebServer 8080)
(.add "/websocket"
(proxy [WebSocketHandler] []
(onOpen [c] (println "opened" c))
(onClose [c] (println "closed" c))
(onMessage [c j] (println c j))))

(.add (StaticFileHandler. "."))
(.start))

(println "server up")

Вот и все. Сервер мало что делает, но работает. Запустите его, если хотите.

java -cp clojure.jar:webbit.jar:netty-3.2.3.Final.jar:clojure-contrib-1.2.0.jar clojure.main server.clj

(примечание: я использую Clojure 1.2)

Если все прошло хорошо, вы должны увидеть «server up», напечатанный на консоли. Мы пока оставим сервер работающим и соберем простой клиент.

Опять же, примеры уже в Интернете дают нам 90% того, что нам нужно. Мы собираемся использовать jquery-websocket , и пример внизу страницы как раз о том, что нам нужно. Следующий код является слегка измененной версией, которая должна соответствовать нашим целям.

<html>
<body>
<h1>WebSocket Demo</h1>
<input id="message" type="text"/>
<section id="content"></section>
<script src="http://www.google.com/jsapi"></script>
<script>google.load("jquery", "1.3")</script>
<script src="http://jquery-json.googlecode.com/files/jquery.json-2.2.min.js">
</script>
<script src="http://jquery-websocket.googlecode.com/files/jquery.websocket-0.0.1.js">
</script>
<script>
var ws = $.websocket("ws://127.0.0.1:8080/websocket", {
events: {
upcased: function(e) { $("#content").html(e.message); }}});

$('#message').change(function(){
ws.send('message', {type: "downcase", message: $("#message").val()});});
</script>
</body>
</html>

Наш клиент не очень большой, но он подключается к веб-сокету и отправляет сообщение в веб-сокет при изменении текста на входе.

Предполагая, что сервер все еще работает, вы сможете загрузить свою страницу.


Ваша страница не загружается?
= (

Какой URL вы использовали? Мне сказали, что http: // localhost: 8080 / не работает так же хорошо, как http://127.0.0.1:8080/

Какой браузер вы использовали? У меня все работает в Chrome (версия 8.0.552.237)

Если ваша страница загружается, ваш сервер должен быть запущен. Вы должны увидеть нечто похожее на следующую строку в консоли вашего сервера.

opened #<NettyWebSocketConnection webbit.netty.NettyWebSocketConnection@8c5488>

Вы также можете напечатать что-нибудь на входе и выйти (или что вы предпочитаете делать, чтобы запустить событие «изменение»). Я набрал «привет» и получил следующую информацию в консоли сервера.

#<NettyWebSocketConnection webbit.netty.NettyWebSocketConnection@8c5488> {"type":"message","data":{"type":"downcase","message":"hello"}}

Ладно все работает Давайте добавим немного поведения на наш сервер. После получения сообщения наш сервер собирается взять текст, поставить его в регистр и отправить обратно клиенту.

Вот обновленная версия server.clj.

(ns server
(:require [clojure.contrib.json :as json]
[clojure.string :as s])
(:import [webbit WebServer WebServers WebSocketHandler]
[webbit.handler StaticFileHandler]))

(defn on-message [connection json-message]
(let [message (-> json-message json/read-json (get-in [:data :message]))]
(.send connection (json/json-str {:type "upcased" :message (s/upper-case message) }))))

(doto (WebServers/createWebServer 8080)
(.add "/websocket"
(proxy [WebSocketHandler] []
(onOpen [c] (println "opened" c))
(onClose [c] (println "closed" c))
(onMessage [c j] (on-message c j))))

(.add (StaticFileHandler. "."))
(.start))

(println "server up")

Новая версия server.clj использует преимущества поддержки json clojure.contrib. Конечным результатом этого является то, что мы можем работать с картами Clojure и в основном игнорировать json в нашем приложении.

После внесения вышеуказанных изменений в server.clj мы можем перезапустить наш сервер, обновить нашу веб-страницу, ввести текст, вставить вкладку из ввода, а затем мы должны увидеть наш текст на веб-странице в верхнем регистре.

И мы закончили. У нас работает клиент-серверное взаимодействие. Мы готовы запустить это в производство. Это так просто.

Возможно, вы заметили несколько вещей, которые делают магию случиться. На сервер мы отправили карту, которая имеет: тип «upcased». Этот тип соответствует событиям, которые определены в нашем клиенте. Jquery-websocket заботится о том, чтобы направить наше новое сообщение в функцию, связанную с upcased. Продолжая эту идею, вы можете отправлять сообщения с сервера разных типов и обрабатывать каждое из них в пользовательском интерфейсе как отдельное событие.

Вот и все. Приложение должно работать, и у вас должно быть все необходимое, чтобы начать расширять возможности приложения. Если у вас возникнут какие-либо проблемы, документация для webbit и jquery-websocket должна помочь вам.