Hallo,
ich hab leider ein Problem mit Websocket-Verbindungen, das ich nicht gelöst bekomme…
Der Client baut eigentlich ganz gewöhnlich und erfolgreich eine Socket-Verbindung auf.
Danach funktioniert die Kommunikation tadellos, bis der Benutzer seine Seite neu lädt (z.B. F5).
Theoretisch bedeutet das doch, dass die Seite kurz verlassen und dann wieder neu aufgebaut wird.
Also wird die Verbindung getrennt und auch wieder neu aufgebaut.
Aber scheinbar bekommt der Server das nicht richtig mit, denn der client kann zwar noch Nachrichten versenden, aber es kommen keine Nachrichten mehr beim ihm an.
Auf dem Server sehe ich, dass beim Wiederverbinden dieselbe Ressource-ID verwendet wird, was wohl schon nicht richtig ist und der Server meldet ein paar Sekunden später, dass der Client disconnected wäre.
Ich habe sogar schon sicherheitshalber ein websocket.close() eingebaut, bevor die Seite beendet wird:
window.onbeforeunload = function() {
websocket.onclose = function () {};
websocket.close()
};
Aber das scheint den Server nicht zu interessieren.
Client-Script:
var wsUri = "ws://10.10.10.123:9000/scripts/server.php";
websocket = new WebSocket(wsUri);
websocket.onopen = function(ev) {
$('#message_box').append("<div class=\"system_msg\">Connected!</div>");
var mymessage = "user";
var msg = {
message: mymessage,
name: myname,
type: mytype
};
websocket.send(JSON.stringify(msg));
}
websocket.onmessage = function(ev) {
var msg = JSON.parse(ev.data);
var utype = msg.type;
var umsg = msg.message;
var uname = msg.name;
$('#message_box').append("<div><span class=\"user_name\">"+uname+"</span>: <span class=\"user_message\">"+umsg+" ("+utype+")</span></div>");
var objDiv = document.getElementById("message_box");
objDiv.scrollTop = objDiv.scrollHeight;
};
websocket.onerror = function(ev){$('#message_box').append("<div class=\"system_error\">Error Occurred - "+ev.data+"</div>");};
websocket.onclose = function(ev){$('#message_box').append("<div class=\"system_msg\">Connection Closed</div>");};
Server-Script:
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);
socket_bind($socket, 0, $port);
socket_listen($socket);
$clients = array($socket);
$clientsid = array();
while (true) {
$changed = $clients;
socket_select($changed, $null, $null, 0, 10);
if (in_array($socket, $changed)) {
$socket_new = socket_accept($socket);
$clients[] = $socket_new;
$header = socket_read($socket_new, 1024);
perform_handshaking($header, $socket_new, $host, $port);
socket_getpeername($socket_new, $ip);
$response = mask(json_encode(array('type'=>'system', 'message'=>$ip.' connected')));
send_message($response,"");
$found_socket = array_search($socket, $changed);
unset($changed[$found_socket]);
}
foreach ($changed as $changed_socket) {
while(socket_recv($changed_socket, $buf, 1024, 0) >= 1)
{
$received_text = unmask($buf);
$tst_msg = json_decode($received_text);
$user_name = $tst_msg->name;
$user_message = $tst_msg->message;
$user_type = $tst_msg->type;
echo "$user_name sent: $user_message (type: $user_type)\r\n";
$erg = array_multi_search($user_name, $clientsid);
if (empty($erg[0][0])) {
array_push($clientsid, array($user_name,$changed_socket));
$response = mask(json_encode(array('type'=>'system', 'name'=>'system', 'message'=>$user_name.' added.')));
send_message($response,"");
foreach($clientsid as $subKey => $subArray){
echo "-->".$subArray[0].":".$subArray[1]."\r\n";
if (empty($subArray[0])) {
unset($clientsid[$subKey]);
}
}
}
$x = explode(":",$user_message);
if ($x[0] <> $user_message) {
$target = $x[0];
array_shift($x);
$user_message = implode($x);
$response_text = mask(json_encode(array('type'=>'whisper', 'name'=>$user_name." (to ".$target.")", 'message'=>$user_message)));
send_message($response_text,$user_name);
} else {
$target = "";
}
$response_text = mask(json_encode(array('type'=>$user_type, 'name'=>$user_name, 'message'=>$user_message)));
send_message($response_text,$target);
break 2;
}
$buf = @socket_read($changed_socket, 1024, PHP_NORMAL_READ);
if ($buf === false) {
$found_socket = array_search($changed_socket, $clients);
socket_getpeername($changed_socket, $ip);
unset($clients[$found_socket]);
foreach($clientsid as $subKey => $subArray){
echo "-->".$subArray[0].":".$subArray[1]."\r\n";
if (($subArray[1] == $changed_socket) OR (empty($subArray[0]))) {
unset($clientsid[$subKey]);
}
}
$response = mask(json_encode(array('type'=>'system', 'message'=>$ip.' disconnected')));
send_message($response,"");
echo $ip." disconnected\r\n";
}
}
}
socket_close($socket);
function send_message($msg,$target) {
global $clients;
global $clientsid;
if (!empty($target)) {
$erg = array_multi_search($target, $clientsid);
}
if ((!empty($target)) AND (!empty($erg[0][0]))) {
echo "sende zu ".$erg[0][0]." mit resource: ".$erg[0][1]."\r\n";
$usertarget = $erg[0][1];
@socket_write($usertarget,$msg,strlen($msg));
} else {
foreach($clientsid as $nr => $client) {
if (substr($client[0],0,9) == "user") {
echo "sende zu ".$client[0]." mit resource: ".$client[1]."\r\n";
$changed_socket = $client[1];
@socket_write($changed_socket,$msg,strlen($msg));
}
}
}
return true;
}
function unmask($text) {
$length = ord($text[1]) & 127;
if($length == 126) {
$masks = substr($text, 4, 4);
$data = substr($text, 8);
}
elseif($length == 127) {
$masks = substr($text, 10, 4);
$data = substr($text, 14);
}
else {
$masks = substr($text, 2, 4);
$data = substr($text, 6);
}
$text = "";
for ($i = 0; $i < strlen($data); ++$i) {
$text .= $data[$i] ^ $masks[$i%4];
}
return $text;
}
function mask($text) {
$b1 = 0x80 | (0x1 & 0x0f);
$length = strlen($text);
if($length <= 125)
$header = pack('CC', $b1, $length);
elseif($length > 125 && $length < 65536)
$header = pack('CCn', $b1, 126, $length);
elseif($length >= 65536)
$header = pack('CCNN', $b1, 127, $length);
return $header.$text;
}
function perform_handshaking($receved_header,$client_conn, $host, $port) {
$headers = array();
$lines = preg_split("/\r\n/", $receved_header);
foreach($lines as $line)
{
$line = chop($line);
if(preg_match('/\A(\S+): (.*)\z/', $line, $matches))
{
$headers[$matches[1]] = $matches[2];
}
}
$secKey = $headers['Sec-WebSocket-Key'];
$secAccept = base64_encode(pack('H*', sha1($secKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));
$upgrade = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" .
"Upgrade: websocket\r\n" .
"Connection: Upgrade\r\n" .
"WebSocket-Origin: $host\r\n" .
"WebSocket-Location: ws://$host:$port/demo/shout.php\r\n".
"Sec-WebSocket-Accept:$secAccept\r\n\r\n";
socket_write($client_conn,$upgrade,strlen($upgrade));
}
function array_multi_search($mSearch, $aArray, $sKey = "") {
$aResult = array();
foreach( (array) $aArray as $aValues) {
if($sKey === "" && in_array($mSearch, $aValues)) $aResult[] = $aValues;
else
if(isset($aValues[$sKey]) && $aValues[$sKey] == $mSearch) $aResult[] = $aValues;
}
return $aResult;
}
LG Marvin