Perl(Protocol::WebSocket)にJava(weberknecht)でつなぐ

2012-01-25T00:00:00+00:00 HTML5 Java JavaScript

要はPerl(Protocol::WebSocket)で作られたWebSocketサーバーにJavaのweberknechtっていうWebSocketライブラリを使って接続してブラウザ側で送信されたメッセージング等を取得したり出来るかっていう検証をやってみた

app.psgi

use strict;
use warnings;
use utf8;
use AnyEvent::Handle;
use Plack::App::File;
use Plack::Builder;
use Protocol::WebSocket::Frame;
use Protocol::WebSocket::Handshake::Server;

my %channel;
my @message;

builder {
    mount "/" => Plack::App::File->new(file => "index.html")->to_app;

    mount "/websocket" => sub {
        my $env = shift;
        my $fh = $env->{"psgix.io"} or return [500,[],[]];

        my $hs = Protocol::WebSocket::Handshake::Server->new_from_psgi($env);
        $hs->parse($fh) or return [500, [], [$hs->error]];

        my $code = sub {
            my ($channel, $message) = @_;

            if (defined $channel and defined $message) {
                my $frame = Protocol::WebSocket::Frame->new(version => $channel->{version}, buffer => $message);

                $channel->{handle}->push_write($frame->to_bytes());
            }
        };

        return sub {
            my $respond = shift;
            my $frame = Protocol::WebSocket::Frame->new(version => $hs->version);
            my $h = AnyEvent::Handle->new(fh => $fh);

            my $c = +{ handle => $h, version => $hs->version };

            $channel{fileno($fh)} = $c;
            $h->push_write($hs->to_string);

            $code->($c, $_) for @message;

            $h->on_read(sub {
                $frame->append($_[0]->rbuf);

                while (my $msg = $frame->next) {
                    push @message, $msg;

                    for (values %channel) {
                        $code->($_, $msg);
                    }
                }
            });

            $h->on_error(sub {
                delete $channel{fileno($fh)};

                $h->destroy;

                undef $h;
            });
            $h->on_eof(sub {
                delete $channel{fileno($fh)};

                $h->destroy;

                undef $h;
            });
        }
    };
};

まぁ普通にProtocol::WebSocketを使うのですが、weberknechtの仕様がdraft-ietf-hybi-thewebsocketprotocol-00で自分の使ってるブラウザの仕様が恐らくは draft-ietf-hybi-thewebsocketprotocol-08っぽいのでProtocol::WebSocket::Frameを利用する場合にはversionを指定しないとブラウザクライアント側は問題無いっぽい(恐らくはパケットにより判別される?)けど、weberknecht側は00しかサポートしていないっぽいのでweberknecht側に投げる際にはちゃんとバージョン指定しないといけないみたいで(ry

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  </head>
  <body>
    <input type="text" id="message" />
    <button onclick="send_message(document.getElementById("message").value)">send</button>
    <div id="messages"></div>
    <script type="text/javascript">
var ws = new WebSocket("ws://localhost:5000/websocket");
ws.onmessage = function(e) {
  var messages = document.getElementById("messages");

  var message = document.createElement("h4");
  message.innerHTML = e.data;

  messages.appendChild(message);
};
ws.onerror = function(e) {
  console.log(e);
};
ws.onclose = function(e) {
  console.log("CLOSE");
};

function send_message(value) {
  ws.send(value);
}
    </script>
  </body>
</html>

至って普通のWebSocketブラウザクライアント側。特に書く事無し

Client.java

import java.net.URI;

import de.roderick.weberknecht.WebSocket;
import de.roderick.weberknecht.WebSocketConnection;
import de.roderick.weberknecht.WebSocketEventHandler;
import de.roderick.weberknecht.WebSocketMessage;

public class Client {
    public static void main(String[] args) throws Exception {
        WebSocket ws = new WebSocketConnection(new URI("ws://localhost:5000/websocket"));
        ws.setEventHandler(new WebSocketEventHandler() {
            @Override
            public void onOpen() {
                System.out.println("[OPEN]");
            }

            @Override
            public void onMessage(WebSocketMessage message) {
                System.out.println("[MESSAGE]: " + message.getText());
            }

            @Override
            public void onClose() {
                System.out.println("[CLOSE]");
            }
        });
        ws.connect();
        ws.send("WebSocket message send from Java(weberknecht)");
    }
}

まぁweberknechtの公式上に載ってるコードそのまま使っちゃって問題無いはず。そんな感じでJavaクライアント側からPerlでProtocol::WebSocketを使って書いたWebSocketサーバーでも接続して云々したり出来るなど

UbuntuでObjective-C