HTML5 WebSocket

HTML5 unterstützt jetzt das Aufbauen von „WebSocket“-Verbindungen. Eine WebSocket Verbindung basiert ähnlich wie HTTP auf dem TCP Protokoll, baut aber eine „dauerhafte“ Verbindung auf. Die Vorteile gegenüber HTTP ist, dass eine Aktion des Servers keine vorhergehende Anfrage des Clients mehr erfordert, wodurch der Server neue Informationen fasst in Echtzeit ausliefern kann. Dadurch kann man eine Menge Traffic und viele unnötige HTTP-Requests sparen, die etwa ein AJAX-JavaScript sonst schicken würde um neue Informationen zu erhalten.
Technisch gesehen baut bei einer WebSocket-Verbindung der Browser mit dem Server eine Verbindung auf, die nach einen Handshake dann bestehen bleibt und über die dann Binär- und Textdaten geschickt werden können.

Leider hat das Protokoll im Handshake einige Sicherheitsprobleme (gehabt?) und sich deshalb ständig verändert. Dieser Artikel bezieht sich also auf die Aktuellste Version (17). Diese wird derzeit von der aktuellsten Chrome Version und anderen Webkit Browsern unterstützt, in Firefox und Opera ist WebSocket wegen der Sicherheitsprobleme derzeit deaktiviert.

Um HTML5 WebSocket zu verwenden ist zunächst ein WebSocket-Server nötig. Ich habe hier nach einer PHP-Variante gesucht und habe dann nach einer Weile folgenden gefunden: php-websocket. Diesen sollte man sich laden und dann kann man ihn per

php -q php-websocket/server/server.php

starten. Jetzt ist ein WebSocket-Server auf „localhost:8000“ zu erreichen. Dort sind derzeit zwei Module geladen, einmal das Modul „echo“ und einmal das Modul „chat“. (Ich werde mich hier nicht mit der Entwicklung eines WebSocket-Server weiter befassen) Das „echo“ Modul nimmt einfach Anfragen entgegen und schickt diese dann an alle Verbundenen Sockets weiter.

Nun kümmern wir uns um die HTML5-Seite von WebSocket, dem User-Frontend. Dafür bauen wir uns erstmal eine einfache HTML5 Seite:





HTML5 WebSocket Test





// hier wird dann das WebSocket-Script reinkommen, siehe unten




Log

Chatbox

Say something

Für die einfache Verwendung des WebSockets habe ich mir eine kleine Wrapper-Library (websocketlib.js) programmiert:

/**
 * Small wrapper library for HTML5 WebSocket
 * 
 * @author Alexander Thiemann 
 * @version 1.0
 * 
 * @param string WebSocket host, eg. ws://localhost:8010/echo
 * @param function Function to be called when socket is connected
 * @param function Function to be called when socket recieves data, takes 1 argument message
 * @param function Function to be called for logging purposes, takes 1 argument log-message
 * 
 * @see http://blog.agrafix.net/2011/11/html5-websocket/
 */
var WebSocketLib = {
	init: function(host, onConnect, onRecv, onLog) {
		this.socket = new WebSocket(host);
		
		this.onLog = onLog;
		this.onRecv = onRecv;
		this.onConnect = onConnect;
		
		this.onLog('Initializing Socket. State: ' + this.socket.readyState);
		
		this.socket.onopen = this._onOpen;
		this.socket.onmessage = this._onMessage;
		this.socket.onclose = this._onClose;
	},
	
	send: function(message) {
		WebSocketLib.socket.send(message);
	},
	
	_onClose: function() {
		WebSocketLib.onLog('Socket Closed.');
	},
	
	_onMessage: function(msg) {
		WebSocketLib.onLog('Recieved new Message from Server: ' + msg.data);
		WebSocketLib.onRecv(msg.data);	
	},
	
	_onOpen: function() {
		WebSocketLib.onLog('Socket is Ready. State: ' + WebSocketLib.socket.readyState);
		
		if (WebSocketLib.socket.readyState == 1) {
			WebSocketLib.onConnect();
		}	
	}
}

Ich denke dort ist alles relativ selbsterklärend. Das WebSocket ist wirklich sehr leicht zu verwenden! Um diese Wrapper-Library zu verwenden, bauen wir in obiges HTML-Grundgerüst bei „// hier wird dann das WebSocket-Script reinkommen, siehe unten“ folgendes ein:

$(document).ready(function() {
	WebSocketLib.init('ws://localhost:8010/echo', 
	function() {
		sockReady();
	},
	function (t) {
		$('#chatbox').append($("

").text(t)); }, function (t) { $('#logbox').append($("

").text(t)); }); function sockReady() { $('#chat').submit(function(e) { e.preventDefault(); var input = $('input[name="message"]'); WebSocketLib.send(input.val()); input.val(""); }); } });

Zuerst warten wir, bis unser HTML-Dokument im Browser aufgebaut ist. Dann geben wir in Zeile 2 an, wo unser WebSocket-Server läuft. Die Funktion in Zeile 4 wird aufgerufen, sobald das WebSocket verbunden ist. Die Funktion Zeile 6-8 wird aufgerufen, wenn eine Nachricht zurückgegeben wird. Die Funktion Zeile 9-11 wird bei Log-Ereignissen (Hauptsächlich zum Debuggen) aufgerufen. Mit WebSocketLib.send(„Nachricht“) in Zeile 19 schicken wir eine Nachricht an den Server.

Wenn nun alles vorbereitet ist, der WebSocket-Server gestartet ist (siehe oben), können wir einem Browser, der WebSocket unterstützt (siehe oben), unsere HTML-Seite aufrufen. Die Log-Ausgabe im HTML-Fenster sieht wie folgt aus:

Initializing Socket. State: 0
Socket is Ready. State: 1

Im Consolenfenster des PHP-Server sehen wir:

2011-11-25 11:26:47 [info] [client 127.0.0.1:30601] Connected
2011-11-25 11:26:47 [info] [client 127.0.0.1:30601] Performing handshake
2011-11-25 11:26:47 [info] [client 127.0.0.1:30601] Handshake sent

Die Verbindung ist nun also aufgebaut. Jetzt sollten wir den „echo“-Server testen. Wir tippen etwas in das Textfeld und schicken es ab. Der Log sagt:

Recieved new Message from Server: test

Und unter „Chat“ steht jetzt „test“. Hat soweit also funktioniert! Jetzt können wir ein neues Browserfenster aufmachen, wieder den Verbindungsvorgang abwarten und dann dort eine Nachricht verschicken. Diese erscheint dann in allen verbundenen Client-Fenstern.

Eigentlich ziemlich einfach zu verwenden, und es öffnet viele neue Möglichkeiten vorallem in Kombination mit Canvas für HTML5-Multiplayer-Games… hoffen wir also, dass es bald von allen Browser voll unterstützt wird! 🙂

 

Sprechblasen mit HTML5, Canvas und JavaScript

Mit HTML5, Canvas und JavaScript kann man mittlerweile eine Menge schöner Grafiken direkt im Browser rendern. Da ich neulich eine flexible Sprechblase benötigt habe, hier der Code dafür:

/**
 * Draw a speech bubble on an HTML5-Canvas
 *
 * @author Alexander Thiemann 
 * @license CC BY-SA 2.0
 * 
 * @param ctx Canvas 2d context
 * @param text Text for the speech bubble
 * @param x bottom left x-coordinate of speech bubble
 * @param y bottom left y-coordinate of speech bubble
 *
 */
function speechBubble(ctx, text, x, y) {
	var messure = ctx.measureText(text);
	
	var w = messure.width;
	var h = 20;
	
	ctx.beginPath();
	ctx.strokeStyle="black";
	ctx.lineWidth="1";
	ctx.fillStyle="rgba(255, 255, 255, 0.8)";
	
	ctx.moveTo(x, y);
	ctx.lineTo(x + (w*0.2), y);
	ctx.lineTo(x + (w*0.2), y+10);
	ctx.lineTo(x + (w*0.3), y);
	ctx.lineTo(x + w, y);
	
	ctx.quadraticCurveTo(x + (w*1.1), y, x + (w*1.1), y-(h*0.2)); // corner: right-bottom
	
	ctx.lineTo(x + (w*1.1), y-(h*0.8)); // right
	
	ctx.quadraticCurveTo(x + (w*1.1), y-h, x + w, y-h); // corner: right-top
	
	ctx.lineTo(x, y-h); // top
	
	ctx.quadraticCurveTo(x - (w*0.1), y-h, x - (w*0.1), y-(h*0.8)); // corner: left-top
	
	ctx.lineTo(x - (w*0.1), y-(h*0.2)); // left
	
	ctx.quadraticCurveTo(x - (w*0.1), y, x, y); // corner: left-bottom
	
	ctx.fill();
	ctx.stroke();
	ctx.closePath();
	
	ctx.textAlign = 'left';
	ctx.fillStyle = '#000';
	ctx.fillText(text, x, y-6);
}

Verwendung:
HTML


JavaScript

var ctx = document.getElementById("bubble").getContext('2d');
speechBubble(ctx, "Das hier ist ein Test!", 5, 40);

Das Resultat:
Realisiert mit HTML5, Canvas und JavaScript

Ziemlich schick, oder? 😉

 

Zippyshare Downloads automatisieren [reloaded]

Heute geht es wieder um Zippyshare-Downloads, bzw. wie man diese einfach automatisieren kann. Da seit meinem letzten Beitrag zu diesem Thema die Seite wieder einige Umstellungen gemacht hat, präsentiere ich hier meine neue AutoIT Lösung:

; #FUNCTION# ====================================================================================================================
; Name ..........: _ZippyLoad
; Description ...: Download a file from zippyshare.com
; Syntax ........: _ZippyLoad($sUrl, $sFilename)
; Parameters ....: $sUrl                - Downloadpage, eg. http://www01.zippyshare.com/view.jsp?locale=de&key=12345678 or http://www01.zippyshare.com/v/12345678/file.html
;                  $sFilename           - Path to where the download should be saved, eg. C:test.mp3
; Return values .: False on error, InetGet-Handle on success
; Author ........: www.agrafix.net
; Modified ......: 17.11.2011 - 15:57
; Remarks .......: None
; Related .......: _ZippyIsComplete
; Link ..........: http://blog.agrafix.net/tag/zippyshare/
; Example .......: No
; License .......: CC BY-NC 3.0
; ===============================================================================================================================
Func _ZippyLoad($sUrl, $sFilename)
	; RegExp
	$sRegExp  = ''
	$sRegExp &= 's*var a = ([0-9]*)%([0-9]*);'
	$sRegExp &= 's*var b = ([0-9]*)%([0-9]*);'
	$sRegExp &= 's*document.getElementById(.dlbutton.).href = "([^"]*)"+(([ab*+-/0-9]*))+"([^"]*)";'
	$sRegExp &= 's*'

	; Extract Host
	$aHostMatches = StringRegExp($sURL, 'http://([^/]*)', 1)
	$sHost = $aHostMatches[0]

	If @error = 1 Or @error = 2 Then
		SetError(1)
		Return False ; Invalid Host
	EndIf

	; Get Downloading Page
	$sSource = _INetGetSource($sURL)

	; Extract Params for Download-URL
	$aMatches = StringRegExp($sSource, $sRegExp, 1)

	If @error = 1 Or @error = 2 Then
		SetError(2)
		Return False ; Downloading failed
	EndIf

	$iVarA = Mod($aMatches[0], $aMatches[1])
	$iVarB = Mod($aMatches[2], $aMatches[3])

	$sMathExpr = StringReplace(StringReplace($aMatches[5], "a", $iVarA), "b", $iVarB)

	$iResult = Execute($sMathExpr)

	$sBaseUrl = $aMatches[4] & $iResult & $aMatches[6]

	$sFullPath = "http://" & $sHost & $sBaseUrl

	; Download File
	$hHandle = InetGet($sFullPath, $sFilename, 1, 1)
	ConsoleWrite("Downloading " & $sFullPath & " to " & $sFilename & @CRLF)

	Return $hHandle
EndFunc

; #FUNCTION# ====================================================================================================================
; Name ..........: _ZippyIsComplete
; Description ...: Check if a download launched with _ZippyLoad is complete
; Syntax ........: _ZippyIsComplete($hHandle)
; Parameters ....: $hHandle             - the handle returned from _ZippyLoad
; Return values .: True if download is complete, False if not
; Author ........: www.agrafix.net
; Modified ......: 17.11.2011 - 15:57
; Remarks .......: None
; Related .......: _ZippyLoad
; Link ..........: http://blog.agrafix.net/tag/zippyshare/
; Example .......: No
; License .......: CC BY-NC 3.0
; ===============================================================================================================================
Func _ZippyIsComplete($hHandle)
	Return InetGetInfo($hHandle, 2)
EndFunc

Die Verwendung dieser Funktionen ist denkbar einfach:

#include 

$h = _ZippyLoad("http://www01.zippyshare.com/view.jsp?locale=de&key=12345678", @ScriptDir & "test.mp3")
While Not _ZippyIsComplete($h)
	Sleep(250)
WEnd
ConsoleWrite("Download complete..." &@CRLF)

Der Code steht zur freien Verwendung unter der CC BY-NC 3.0 Lizenz.

 

Manager’s Life V2

Die Entwicklung von Manager’s Life V2 geht langsam auf ein Release zu – deshalb wird die aktuelle Version am 25.11.2011 beendet! Wir bedanken uns bei allen, die bisher das Spiel gespielt haben und würden uns freuen euch wieder bei Version 2 begrüßen zu dürfen.

Das alte Spielkonzept wird in Version 2 komplett über den Haufen geworden und das Spiel wurde von Grund auf neu Programmiert. Erhalten bleibt eigentlich nur das Design! Ich möchte jetzt noch nicht zu viel verraten, aber es wird aufjedenfall ein Online-Spiel, von dem es in dieser Form erst sehr wenige gibt. Es nutzt die modernen HTML5 und JavaScript Techniken komplett aus, ist sehr grafisch und funktioniert auch auf mobilen Endgeräten.

Lasst euch überraschen!

Wer einen Beta-Key möchte, um in der Closed Beta mitzuspielen, schickt bitte eine Email an allypage@gmail.com. Die Keys sind jedoch nur sehr begrenzt erhältlich!

Manager’s Life