LoginSignup
17
18

More than 5 years have passed since last update.

Vert.xでチャットサーバー

Posted at

Instan Vert.xを読みながらサンプルコードを試してみる。
今回はChat Server。
本の中のコードはほとんどJavaScriptで書かれているのだけれども、Javaの方がAPIを追っかけやすいのとJava8の勉強をかけてJavaで再実装。
コードはこんな感じ。


public class ChatServer extends Verticle {

  private static final String MESSAGE_BROADCAST_ADDRESS = "broadcast_address";

  public void start() {
    NetServer netserver = vertx.createNetServer();
    netserver.connectHandler((NetSocket socket) -> {
      InetSocketAddress remoteAddr = socket.remoteAddress();
      String addr = String.format("%s:%d", remoteAddr.getAddress(), remoteAddr.getPort());
      socket.write(String.format("Welcome to the chat %s!", addr));
      // コネクション1つにつき1つのハンドラを登録する。
      Handler<Message<String>> messageHandler = (event) -> {
        socket.write(event.body());
      };
      vertx.eventBus().registerHandler(MESSAGE_BROADCAST_ADDRESS, messageHandler);
      // ソケットからメッセージを受け取ったときにEventBusを通じてメッセージをpublishする。
      socket.dataHandler((Buffer data) -> {
        ZonedDateTime now = ZonedDateTime.now();
        String msg = String.format("%s<%s>: %s", now, addr, data);
        vertx.eventBus().publish(MESSAGE_BROADCAST_ADDRESS, msg);
      });
      // コネクションが閉じられたらEventBusから閉じられたコネクションのメッセージハンドラを取り除く。
      socket.closeHandler((Void event) -> {
        vertx.eventBus().unregisterHandler(MESSAGE_BROADCAST_ADDRESS, messageHandler);
      });
    });
    netserver.listen(1234);

  }
}

サーバーへの接続は

telnet localhost 1234

でできる。

closeハンドラの所は本に載っていなかったけど、実装しておいた。ソケットにつなぐたびにEventBusにハンドラを登録する仕組みなので、接続がとじられた時にハンドラを除く処理がないとリークするはず。

Clojureでも書いてみた。


(ns chatsample-clj.core
  (:require [vertx.core :as vertx]
            [vertx.net :as net]
            [vertx.stream :as stream]
            [vertx.eventbus :as eb]))
(def ^:dynamic **broadcast-address** "broadcast-address")
(defn -connect-handler [sock]
  (let [message-handler (fn [event] (stream/write sock event))
        remote-addr (net/remote-address sock)
        addr-info (format "%s:%d"  (:host remote-addr) (:port remote-addr))
        data-handler (fn [data] (let [now (java.time.ZonedDateTime/now)]
                                      (eb/publish **broadcast-address**
                                                  (format "%s<%s> %s" now addr-info data))))]
    (eb/on-message **broadcast-address** message-handler)
    (-> sock
      (stream/write (format "Welcome to the chat %s" addr-info))
      (stream/on-data data-handler)
      (net/on-close #(eb/unregister-handler **broadcast-address** message-handler)))))
(defn init[]
  (let [server (net/server)]
    (-> server
      (net/on-connect -connect-handler)
      (net/listen 1234 "localhost"))))

ソースコードはこちらにもあります。
Java版
Clojure版

17
18
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
18