Ankündigung

Einklappen
Keine Ankündigung bisher.

[Erledigt] WebSocket - Server disconnectet wenn FireFox oder Chrome reloadet

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • [Erledigt] WebSocket - Server disconnectet wenn FireFox oder Chrome reloadet

    Hallo zusammen,

    ich befasse mich testweise gerade mit WebSockets und habe im Netz einige fertige Scripts gefunden.
    Nach hin und her Schreiberei funktioniert es nun auch einigermaßen.
    Doch ich habe ein merkwürdiges Problem. Mehrere Clients connecten problemlos und können miteinander schreiben.

    Doch: Öffne ich einen Client im Safari, einen im FireFox und einen in Chrome, passiert nichts wenn ich den Safari-Client einfach schließe.
    Schließe ich allerdings den FireFox oder Chrome-Browser disconnectet er alle anderen Clients. (FireFox sendet beim verlassen wohl noch ein "?" - Chrome ein Zeichen, welches nicht angezeigt wird (vielleicht ein leeren String..?).

    Der Server stürzt nicht ab, und gibt auch keine Fehler aus. Man kann danach einfach wieder zum Server verbinden.

    Hier nun das Script: (Ja, es ist unsauberes PHP, PHP4&5 gemischt....) Wie gesagt, ist ausm Netz zusammengebaut und nicht die finale Version..

    Das Problem SCHEINT mir hier zu liegen:
    PHP-Code:
    elseif($bytes == 0){
                            
    $this->disconnect($socket);
                        } 
    Diese Funktion wird wohl für alle Sockets aufgerufen, sobald dieses "END"-Zeichen von FF oder Chrome rein kommt.

    PHP-Code:
    <?php  

    // Usage: $master=new WebSocket("localhost",12345);

    class WebSocket{
      private 
    $master;
      private 
    $sockets = array();
      private 
    $users   = array();
      private 
    $debug   false;
      
      function 
    __construct($address,$port){
        
    error_reporting(E_ALL);
        
    set_time_limit(0);
        
    ob_implicit_flush();

        
    $this->master=socket_create(AF_INETSOCK_STREAMSOL_TCP)     or die("socket_create() failed");
        
    socket_set_option($this->masterSOL_SOCKETSO_REUSEADDR1)  or die("socket_option() failed");
        
    socket_bind($this->master$address$port)                    or die("socket_bind() failed");
        
    socket_listen($this->master)                                     or die("socket_listen() failed");
        
    $this->sockets[] = $this->master;
        
    $this->say("Server Started : ".date('Y-m-d H:i:s'));
        
    $this->say("Listening on   : ".$address." port ".$port);
        
    $this->say("Master socket  : ".$this->master."\n");

        while(
    true){
            
    $changed $this->sockets;
            
    $wirte = array();
            
    $except = array();
            
            
    socket_select($changed,$write,$except,NULL);
            foreach(
    $changed as $socket){
            
                
    # Wenn Mastersocket, dann neuer Client
                
    if($socket==$this->master){
                    
    $client=socket_accept($this->master);
                    if(
    $client<0){ $this->log("socket_accept() failed"); continue; }
                    else{ 
    $this->connect($client); }
                }
                
                
    # Daten von einem Client
                
    else{
                
                    
    $user $this->getuserbysocket($socket);
                    
    $bytes '';
                    
                    if(
    $user) {
                        
    # daten lesen
                        
                        
    $bytes = @socket_recv($socket$buffer20480);
                        
                        
    #$data=null; 
                        #while($bytes = @socket_recv($socket, $r_data, 2048, MSG_DONTWAIT)){
                        #    $data.=$r_data;
                        #}
                        
                        # User schon gehandshaked?
                        
    if(!$user->getHandshake()){
                            
    $this->dohandshake($user,$buffer);
                        }
                        elseif(
    $bytes == 0){
                            
    $this->disconnect($socket);
                        }
                        else{
                            
    $this->process($user,$this->unwrap($buffer));
                        }
                    }
                }
            }
        }
      }

      function 
    process($user,$msg){
        
    /* Extend and modify this method to suit your needs */
        /* Basic usage is to echo incoming messages back to client */
        
    $this->send($user->getSocket(),$msg);
      }

      function 
    send($client,$msg){ 
        
    $this->say("> ".$msg);
        
    $msg $this->wrap($msg);
        
    socket_write($client,$msg,strlen($msg));
        
    #$this->say("! ".strlen($msg));
      

      
      function 
    sendToAll($msg){ 
        
    $this->say("> ".$msg);
        
    $msg $this->wrap($msg);
        
        foreach(
    $this->users as $user){
            
    socket_write($user->getSocket(),$msg,strlen($msg));
        }
        
        
    #$this->say("! ".strlen($msg));
      


        function 
    connect($socket){
            
    $user = new User();
            
    $user->setID(uniqid());
            
    $user->setSocket($socket);
            
    array_push($this->users,$user);
            
    array_push($this->sockets,$socket);
            
    $this->log($socket." CONNECTED!");
            
    $this->log(date("d/n/Y ")."at ".date("H:i:s T"));
        }

        function 
    disconnect($socket){
            
    # User nach socket Suchen
            
    $found=null;
            
    $n=count($this->users);
            for(
    $i=0;$i<$n;$i++){
                if(
    $this->users[$i]->getSocket()==$socket){ $found=$i; break; }
            }
            if(!
    is_null($found)){ 
                
    array_splice($this->users,$found,1);
            }
            
            
    # Socket aus Liste suchen und schließen
            
    $index=array_search($socket,$this->sockets);
            if(
    $index>=0){
                
    array_splice($this->sockets,$index,1);
            }
            
            @
    socket_shutdown($socket2);
            
    socket_close($socket);
            
    $this->say($socket." DISCONNECTED!");
            
        }

      function 
    dohandshake($user,$buffer){
        
    $this->log("\nRequesting handshake...");
        
    $this->log($buffer);
        
    $this->log("Handshaking...");
        
        
    // Determine which version of the WebSocket protocol the client is using
        
    if(preg_match("/Sec-WebSocket-Version: (.*)\r\n/ "$buffer$match))
            
    $version $match[1];
        else {
            
    $this->log("Client doens't support WebSocket");
            return 
    false;
        }
        
        
    $this->log("Client WebSocket version {$version} from 13");
        if(
    $version == 13)
        {
            if(
    preg_match("/GET (.*) HTTP/"$buffer$match))
                
    $root $match[1];
            if(
    preg_match("/Host: (.*)\r\n/"$buffer$match))
                
    $host $match[1];
            if(
    preg_match("/Origin: (.*)\r\n/"$buffer$match))
                
    $origin $match[1];
            if(
    preg_match("/Sec-WebSocket-Key: (.*)\r\n/"$buffer$match))
                
    $key $match[1];
                    
            
    // Generate our Socket-Accept key based on the IETF specifications
            
    $acceptKey $key.'258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
            
    $acceptKey base64_encode(sha1($acceptKeytrue));
        
            
    $upgrade "HTTP/1.1 101 Switching Protocols\r\n".
                       
    "Upgrade: websocket\r\n".
                       
    "Connection: Upgrade\r\n".
                       
    "Sec-WebSocket-Accept: $acceptKey".
                       
    "\r\n\r\n";
        
            
    socket_write($user->getSocket(), $upgradestrlen($upgrade));
            
    $user->setHandshake(true);
            
    $this->say("Handshake successfully done!");
            return 
    true;
        }
        else 
        {
            
    $this->log("Client is trying to use an unsupported WebSocket protocol ({$version})");
            return 
    false;
        }   
        
        
    $this->log($upgrade);
        
    $this->log("Done handshaking...");
        
    $this->say("New User");
        return 
    true;
      }
      
      function 
    calcKey($key1,$key2,$l8b){
            
    //Get the numbers
            
    preg_match_all('/([\d]+)/'$key1$key1_num);
            
    preg_match_all('/([\d]+)/'$key2$key2_num);
            
    //Number crunching [/bad pun]
            
    $this->log("Key1: " $key1_num implode($key1_num[0]) );
            
    $this->log("Key2: " $key2_num implode($key2_num[0]) );
            
    //Count spaces
            
    preg_match_all('/([ ]+)/'$key1$key1_spc);
            
    preg_match_all('/([ ]+)/'$key2$key2_spc);
            
    //How many spaces did it find?
            
    $this->log("Key1 Spaces: " $key1_spc strlen(implode($key1_spc[0])) );
            
    $this->log("Key2 Spaces: " $key2_spc strlen(implode($key2_spc[0])) );
            if(
    $key1_spc==0|$key2_spc==0){ $this->log("Invalid key");return; }
            
    //Some math
            
    $key1_sec pack("N",$key1_num $key1_spc); //Get the 32bit secret key, minus the other thing
            
    $key2_sec pack("N",$key2_num $key2_spc);
            
    //This needs checking, I'm not completely sure it should be a binary string
            
    return md5($key1_sec.$key2_sec.$l8b,1); //The result, I think
      
    }

      function 
    getuserbysocket($socket){
        
    $found=null;
        foreach(
    $this->users as $user){
          if(
    $user->getSocket()==$socket){ $found=$user; break; }
        }
        return 
    $found;
      }

      function     
    say($msg=""){ echo $msg."\n"; }
      function     
    log($msg=""){ if($this->debug){ echo $msg."\n"; } }
      
    #function    wrap($msg=""){ return chr(0).$msg.chr(255); }
      #function  unwrap($msg=""){ return substr($msg,1,strlen($msg)-2); }
      
      
      
        ## UNMASK
        
    private function unwrap($payload) {
            
    $length ord($payload[1]) & 127;
            
            if(
    $length == 126) {
                
    $masks substr($payload44);
                
    $data substr($payload8);
            }
            elseif(
    $length == 127) {
                
    $masks substr($payload104);
                
    $data substr($payload14);
            }
            else {
                
    $masks substr($payload24);
                
    $data substr($payload6);
            }
            
            
    $text '';
            for (
    $i 0$i strlen($data); ++$i) {
                
    $text .= $data[$i] ^ $masks[$i%4];
            }
            return 
    $text;
        }
        
        
        private function 
    wrap($text) {
            
    // 0x1 text frame (FIN + opcode)
            
    $b1 0x80 | (0x1 0x0f);
            
    $length strlen($text);
            
            if(
    $length <= 125)         
                
    $header pack('CC'$b1$length);     
            elseif(
    $length 125 && $length 65536)
                
    $header pack('CCS'$b1126$length);
            elseif(
    $length >= 65536)
                
    $header pack('CCN'$b1127$length);
        
            return 
    $header.$text;
        }

    }

    class 
    User{
        private 
    $id;
        private 
    $socket;
        private 
    $handshake;
        private 
    $name 'none';
        
        public function 
    setID($id) {
            
    $this->id $id;
        }
        public function 
    getID() {
            return 
    $this->id;
        }
        
        public function 
    setSocket($socket) {
            
    $this->socket $socket;
        }
        public function 
    getSocket() {
            return 
    $this->socket;
        }
        
        public function 
    setHandshake($hs) {
            
    $this->handshake $hs;
        }
        public function 
    getHandshake() {
            return 
    $this->handshake;
        }
        
        public function 
    setName($name) {
            
    $this->name $name;
        }    
        
    }

    ?>
    Hoffe jemand kann mir helfen.

    Beste Grüße & Danke im Voraus.

    paD

  • #2
    Huhu,

    Problem gefunden: ich habe jedem Client einfach alles von den anderen Clients gesendet. Dieses "K.O." Zeichen von FireFox oder Chrome, beendete dann auch die anderen Streams....

    paD

    Kommentar

    Lädt...
    X