Serwer do WebSocket'ów

Wraz z nadejściem HTML5 jest wprowadzana obsługa WebSocket'ów - czyli strumieniowych połączeń do serwera. Po stronie klienta implementacja jest banalna - kilka linijek i połączenie ustanowione. Częściej problemem jest znalezienie serwera, który mógłby nam posłużyć chociażby do celów testowych. W tym celu wybrałem dwa serwery (w Pythonie i PHP) i uruchomiłem na nich echo serwery.


Należy także pamiętać, że w międzyczasie (ostatnia zmiana jest zapisana jako maj 2010) nastąpiła zmiana metody handshaking'u w WebSocket'ach z 75 do 76. Co istotne Chrome dawniej obsługiwał handshaking 75 natomiast obecnie tylko wersję 76, więc trzeba uważać na przykłady znalezione w sieci ponieważ mogą być nieaktualne i w rezultacie to co działało pół roku temu teraz może już nie działać.

Klient WebSocket

Jak już wspomniałem klient jest banalnie prosty (w przypadku echo serwera), bo całą robotę robi przeglądarka. Minimalna wersja połączenia to utworzenie obiektu WebSocket z adresem serwera jako parametr. Następnie definiujemy zdarzenia np. onopen (po otwarciu połączenia), onmessage (po otrzymaniu połączenia) czy onclose (po zamknięciu połączenia). Wiadomość wysyłamy metodą send obiektu WebSocket.

var ws = new WebSocket("ws://localhost:12345/"); 
ws.onopen = function() { 
  console.log('connected');
  ws.send("HELLO!"); 
}; 
ws.onmessage = function (e) { console.log(e.data); }; 
ws.onclose = function() { console.log('closed'); };

Pełna wersja dokumentacji WebSocket API znajduje się na stronach w3c.

Serwer Tornado - Python

W przypadku Python'a warto skorzystać z serwera zastosowanego do serwisu FriendFeed - Tornado. Generalnie jest to pełna wersja serwera HTTP, natomiast istnieje możliwość wykorzystania jedynie WebSocket'ów.
Prosty echo serwer wykorzystuje klasę WebSocketHandler, która obsługuje połączenia przez WebSocket. W celu nadpisania domyślnych akcji definiujemy metody open (podczas otwarcia), on_message (po otrzymaniu wiadomości), on_close (podczas zamykania portu). Pisanie do strumienia jest możliwe poprzez metodę write_message obiektu WebSocketHandler.
import tornado.httpserver

import tornado.ioloop
import tornado.options
import tornado.web
import tornado.websocket

from tornado.options import define, options

define("port", default=8888, help="run on the given port", type=int)

class EchoWebSocket(tornado.websocket.WebSocketHandler):
 def open(self):
  print "WebSocket opened"

 def on_message(self, message):
  self.write_message(u"Napisales: " + message)

 def on_close(self):
  print "WebSocket closed"

def main():
 tornado.options.parse_command_line()
 application = tornado.web.Application([
     (r"/", EchoWebSocket),
     ])
 http_server = tornado.httpserver.HTTPServer(application)
 http_server.listen(options.port)
 tornado.ioloop.IOLoop.instance().start()


if __name__ == "__main__":
 main()
Aplikację uruchamiamy z konsoli poleceniem
python websocket.py
Domyślnie (tak jak jest zdefiniowane w przykładzie) aplikacja uruchamia się na porcie 8888, więc dostęp uzyskamy poprzez połączenie z ws://localhost:8888.
Jeżeli chcecie wiedzieć więcej o Tornado to zapraszam do dokumentacji.

Serwer phpwebsocket - PHP

Tuż po uruchomieniu WebSocket'ów na Chromie powstał pierwszy serwer w PHP - phpwebsocket. W chwili obecnej jego wersja jest z lutego, więc nie obsługuje najnowszego handshaking'u - natomiast można to szybko załatać stosując klasę Andrei Giammarchi'ego - WebSocketHandshake. Dodanie/includowanie tego kodu oraz drobna zmiana w funkcji/metodzie dohandshake (linia ok. 85-100) pozwala dostosować serwer do nowych standardów.
//list($resource,$host,$origin) = $this->getheaders($buffer);
$this->log("Handshaking...");
$upgrade = WebSocketHandshake($buffer);

I mamy znów działające połączenie. Pamiętam, że był to bardzo fajny serwer do testów (zwłaszcza dla znających PHP'a), więc zachęcam do wypróbowania.

Znalazłem też inną wersję, która także merge'uje dwa wyżej opisane projekty - może także warto spróbować :)
http://bohuco.net/blog/2010/07/php-websocket-server-the-handshake/

Aplikację uruchamiamy jednak nie przez przeglądarkę internetową, a z konsoli komendą
php serv.php

Domyślnie serwer odpala się na porcie 12345, więc jeżeli korzystamy z niego lokalnie to połączenie w WebSocket'ach musimy ustawić na ws://localhost:12345/

Hosting

Generalnie do odpalenia swojego serwera na hostingach konieczne jest posiadanie dostępu do konsoli (i oczywiście odpowiednie prawa i odpowiednio skonfigurowany firewall). Podobno w najbliższym czasie Google ma umożliwić uruchamianie własnych serwerów WebSocket na App Engine. Mi udało się uruchomić przykładowy serwer Tornado na hostingu w kei.pl. W przypadku home.pl lub innych przypuszczalnie będziemy musieli wykupić serwer dedykowany.

Wsparcie przeglądarek

Najnowsze przeglądarki obsługują jedynie nowszą wersję handshakingu czyli 76 - a do nich należą Chrome 4, Opera 10.70, Firefox 4 (obecnie beta), Safari 5. Co ciekawe z tego co zauważyłem to na mobilne urządzenia jedynie najnowszy Firefox 4 beta obsługuje WebSocket'y (w iPhonie najnowszy iOS4 w wersjach beta podobno miał uruchomioną obsługę, natomiast w ostatecznej wersji została wycofana).
Ciekawą stronę przygotowała Opera, gdzie można łatwo i szybko dostać odpowiedź czy Twoja przeglądarka obsługuje WebSocket'y - http://testsuites.opera.com/websockets/.

Prześlij dalej:

4 komentarze:

openid pisze...

Jak mi brakowało stałego połączenia z serwerem... Nareszcie!

Radoslaw pisze...

Witam!
Mam problem z napisaniem działającego echo serwera w javie dla websocket. Dodam że mam oczywiście chrome 8 wszystko co niezbędne włączone. Czy byłbyś tak miły i mógłbyś przesłać mi kod najprostszego echo serwera jaki tylko da się napisać? mam zamiar implementować tą technologie we własnych projektach ale nie mam ochoty korzystać z gotowych serwerów.
Pozdrawiam

Michał Biniek pisze...

Z tego co wyszukałem to jeden serwer javowy to http://jwebsocket.org/ lub http://narup.blogspot.com/2010/01/jwebsocket-simple-java-based-html5.html

Niestety nie siedzę w Javie więc nie jestem w stanie udostępnić kodu, bo go niestety nie mam :)

Nie wiem też czy implementowanie teraz WebSocket'ów to dobry moment, ponieważ wykryto lukę w handshakingu i nie wiadomo czy nie będzie zmieniana - przez co trzeba będzie znów nanosić poprawki.

No i też przez to Opera i Firefox wyłączyły tymczasowo WebSockety - do czasu opracowania nowej wersji.

Anonimowy pisze...

Dla osób błądzących jak ja po temacie. Wygodna obsługa WebSocket na nodeJS: socket.io . Gdy przeglądarka nie obsługuje WS, socketIO próbuje połączyć się alternatywną drogą (dzięki temu nie trzeba przebudować strony dla IE - biblioteka po prostu będzie słała to samo za pomocą chociażby JSONP lub iframe).

Prześlij komentarz