Ankündigung

Einklappen
Keine Ankündigung bisher.

socket_read() im blocking modus

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

  • socket_read() im blocking modus

    Guten Tag liebe PHPler,

    ich habe eine kleine MVC Implementation mit integriertem HTTP Server geschrieben. Diese funktioniert soweit. Das Problem besteht darin den Status des Sockets abzufragen. In POST Requests die nicht mit einem identifizierbarem Ende aufhören kann ich so nicht auslesen ohne vorher ihre Bytelänge zu kennen.

    Das Script wartet solange bis Daten nach gesendet werden, dies wird aber nicht geschehen.

    PHP-Code:
    <?php

    class Server_Socket {
        private 
    $socket;
        private 
    $response;
        private 
    $request;
        private 
    $disp;
        public 
    $dbs;
        
        public function 
    __construct() {
            
    $this->socket socket_create_listenServer_Config::PORT );
            
    socket_set_nonblock$this->socket );
            
    $this->dbs = new Server_Pool_Database;
            
            
    Server_Cron::init();
            
            
    //Alle Crons einrichten
            
    Server_Cron::add( array( $this->dbs"check" ), ( 60 ) );
            
    Server_Cron::add"Server_Statistic::createShot", ( 15 60 ) );
            
    Server_Cron::add"Server_Session::checkSessions"60 );
            
            if( 
    PHP_OS != 'WINNT' ) {
                
                
    $fork = new Server_ForkServer_Config::CHILDS$this );    
            }
            
            else {
                
    $this->listen();    
            }
        }
        
        public function 
    listen() {
            
    $this->response = new Server_Http_Response;
            
    $this->request = new Server_Http_Request;
            
    $this->disp = new MVC_Dispatcher;
            
            if( 
    PHP_OS == 'WINNT' ) {
                while( 
    ) {
                    
    Server_Cron::handle( );

                    while( 
    $conn = @socket_accept$this->socket ) ) {
                        
    socket_set_block$conn );
                        
    $this->handleRequest$conn );    
                    }
                }
            }
            
            else {
                while( 
    ) {
                    while( 
    $conn = @socket_accept$this->socket ) ) {
                        
    socket_set_block$conn );
                        
    $this->handleRequest$conn );    
                    }
                }
            }
        }
        
        public static function 
    readFromSocket$conn$end = array( "\n" => "" ) ) {
            
    $ret "";
            
            do {
                
    $read socket_read$conn);
                
    $ret .= $read;
            } while( !isset( 
    $end[$read] ) );
            
            return 
    $ret;
        }
        
        private function 
    handleRequest$conn ) {
            try {
                
    $start microtimetrue );
                
                
    $this->request->reset();
                
    $this->request->newRequest$conn );
            
                
    $this->response->reset();
                
    $this->response->httpCode200 );
                
                if( !isset( 
    $this->request->path['extension'] ) || in_array$this->request->path['extension'], $this->disp->supported() ) ) {
                    
    $this->disp->root$this->request$this->response );    
                    
    $this->response->send$conn );
                }            
                
                elseif( isset( 
    Server_Mime::$mime[$this->request->path['extension']] ) ) {
                    
    $this->response->setHeader"Content-Type"Server_Mime::$mime[$this->request->path['extension']] );
                    
    $this->response->sendFile"www/"$this->request->conf['main']['document-root'] ."/static/"$this->request->url['path'], $conn );    
                }
                
                else {
                    
    $this->response->httpCode404 );
                    
    $this->response->setContent'File not Found!' );
                    
    $this->response->send$conn );
                  }
            }
            
            catch( 
    Server_Http_Exception $e ) {
                
    $this->response->reset();
                
    $this->response->httpCode$e->getCode() );
                
    $this->response->setContent$e->getMessage() );    
                
    $this->response->send$conn );
            }
        }
    }

    ?>
    Und zwar geht es hier um die statische funktion readFromSocket die bis zu einem \n ( Zeilenumbruch liest ) und dann aufhört und den gelesenden String zurück gibt. Das Problem ist wie gesagt das beim letzten lesen kein Zeilenumbruch ist und er unendlich ( bzw. timeout ) auf ein weiteres Byte wartet.


  • #2
    Du brauchst ein non-blocking socket...

    edit: warum ist bei dir \n ein Zeichen dafür, das die Übertragung endet? Auf Stream-Ebene muss jedes Byte durchgehen können, die Contentlänge bestimmt, wieviele Daten gelesen werden müssen.
    Über 90% aller Gewaltverbrechen passieren innerhalb von 24 Stunden nach dem Konsum von Brot.

    Kommentar


    • #3
      Es gibt zum Beispiel beim Header lesen nach jedem Header einen Zeilenumbruch. Damit ich jeden Header einzelnd lesen kann gibt mir die funktion nur bis zum nächsten Zeilenumbruch den String zurück.

      Das mit non block hatte ich auch schon. Das Problem dabei ist das der schreibbuffer nicht schnell genug ist und geschriebende Bytes nicht sendet.

      Kommentar


      • #4
        RFC2616, 4.4 Message Length ?

        Kommentar


        • #5
          Zitat von Remon Beitrag anzeigen
          Das mit non block hatte ich auch schon. Das Problem dabei ist das der schreibbuffer nicht schnell genug ist und geschriebende Bytes nicht sendet.
          Dann hast du es vlt. falsch implementiert. Hast du die Hinweise zu socket_write() beachtet?
          socket_write() does not necessarily write all bytes from the given buffer. It's valid that, depending on the network buffers etc., only a certain amount of data, even one byte, is written though your buffer is greater. You have to watch out so you don't unintentionally forget to transmit the rest of your data.
          Du kannst jedenfalls nicht den gleichen Code verwenden, wie bei sequentiellem Versenden. Non-Blocking heisst, alle Funktionen kehren *sofort* wieder zurück und geben Hinweise darauf, was passieren könnte, wenn die Voraussetzungen nicht erfüllt sind (accept() ohne Clientanfrage liefert z.B. WSAWOULDBLOCK, ein Hinweis darauf, das bei einem blocking-socket dieser blockieren würde um auf einen Client zu warten...)

          Das heisst, man muss anders an die Sache rangehen und immer vorher prüfen (peek) was passieren würde. Beim Senden musst du immer noch abfragen, ob auch alle Daten gesendet wurden, die du bereitgestellt hast und eventuell "nachliefern"... asynchrone Operationen verlangen asynchrones Handeln, du musst dann selber machen, was dir im blocking modus der Netzwerktreiber abnimmt (Pufferung von Daten, Häppchenweises Senden o. Empfangen).
          Über 90% aller Gewaltverbrechen passieren innerhalb von 24 Stunden nach dem Konsum von Brot.

          Kommentar

          Lädt...
          X