2015-06-28 4 views
6

Ich habe versucht, einen Thread zu verwenden, Socket-Verbindung zu verwalten. Doch zwischen den Ausführungen meines Prozess/Threads, wird der Sockel nicht gesäubert und ich bekomme die Ausnahme:PHP, wie zum Freigeben von Socket

socket_create_listen(): nicht mehr der angegebenen Adresse binden [98]: Adresse bereits im Einsatz in .. Es wird nach etwa 1 Minute gereinigt.

Ich habe im Internet gesucht, konnte aber keine Lösung finden. Auch, wenn Sie den Code in der while (1) Schleife entfernen und zweimal meine PHP-Datei ausführen, wird es auch den gleichen Fehler geben. Ich hätte erwartet, dass alle Ressourcen mit Prozess-Exit gereinigt werden.

<?php 
date_default_timezone_set('UTC'); 

echo date("H:i:s")."\tINFO: Starting my test\n"; 
$socket = null; 

//start our test 
try { 
    echo date("H:i:s")."\tINFO: Setup socket for 1st time\n"; 
    setupSocket(); 
    usleep(100000); 

    //send request to socket via curl 
    $command = 'curl -s --no-buffer -d "{\"action\":\"getStatus\"}" -o socket.txt http://localhost:13000 > socket.log 2>&1 &'; 
    exec($command); 
    usleep(100000); 

    echo date("H:i:s")."\tINFO: Now processing request\n"; 
    processRequest(); 

    echo date("H:i:s")."\tINFO: Close socket\n"; 
    closeSocket(); 
} catch (Exception $e) { 
    echo date("H:i:s")."\tERROR: ".$e->getMessage() ."\n"; 
} 

while(1) { 
    try {   
     echo date("H:i:s")."\tINFO: Try again to set socket...\n"; 
     setupSocket(); 
     usleep(100000); 

     echo date("H:i:s")."\tINFO: Close socket\n"; 
     closeSocket(); 
     break; 
    } catch (Exception $e) { 
     echo date("H:i:s")."\tERROR: ".$e->getMessage() ."\n"; 
     sleep(5); 
    } 
} 

function setupSocket($port=13000) { 
    global $socket, $logger; 

    //Warning: socket_create_listen(): unable to bind to given address [98]: Address already in use in ... 
    $socket = @socket_create_listen($port); 
    if(!$socket) { 
     throw new Exception('Failed to open socket with error \''.socket_strerror(socket_last_error()).'\''); 
    } 
    if(!socket_set_nonblock ($socket)) { 
     throw new Exception('Failed to set the socket as non blocking with error \''.socket_strerror(socket_last_error($socket)).'\''); 
    } 
    //if(!socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1)) { 
    // throw new Exception('Failed to set option \''.socket_strerror(socket_last_error($socket)).'\''); 
    //} 
} 

//http://php.net/manual/en/function.socket-close.php 
//http://php.net/manual/en/function.socket-shutdown.php 
function closeSocket() { 
    global $socket, $logger; 

    //$arrOpt = array('l_onoff' => 1, 'l_linger' => 0); 
    //socket_set_block($socket); 
    //socket_set_option($socket, SOL_SOCKET, SO_LINGER, $arrOpt); 
    if(!socket_shutdown($socket, 2)) { 
     throw new Exception('Failed to shutdown socket with error \''.socket_strerror(socket_last_error($socket)).'\''); 
    } 
    socket_close($socket); 
} 

function processRequest() { 
    global $socket; 
    $client = socket_accept($socket); 
    if ($client) { 
     echo date("H:i:s")."\tINFO: Got connection\n"; 
     //we don't care much about the content since this is a test, but still we read :) 
     $request = socket_read($client, 1000000); 
     $response = array( 
       "head" => array(
        "HTTP/1.0 200 OK", 
        "Content-Type: application/json" 
       ), 
       "body" => json_encode(array('Status'=>true)) 
      ); 
     $response['head'][] = sprintf("Content-Length: %d", strlen($response["body"])); 
     socket_write($client, implode("\r\n", $response['head'])); 
     socket_write($client, "\r\n\r\n"); 
     socket_write($client, $response['body']); 
     socket_close($client); 

    } else { 
     echo date("H:i:s")."\tINFO: Got no connection\n"; 
    } 
} 
?> 

Ergebnis:

16:05:05 INFO: Starting my test 
    16:05:05 INFO: Setup socket for 1st time 
    16:05:05 INFO: Now processing request 
    16:05:05 INFO: Got connection 
    16:05:05 INFO: Close socket 
    16:05:05 INFO: Try again to set socket... 
    16:05:05 ERROR: Failed to open socket with error 'Address already in use' 
    16:05:10 INFO: Try again to set socket... 
    16:05:10 ERROR: Failed to open socket with error 'Address already in use' 
    16:05:15 INFO: Try again to set socket... 
    16:05:15 ERROR: Failed to open socket with error 'Address already in use' 
    16:05:20 INFO: Try again to set socket... 
    16:05:20 ERROR: Failed to open socket with error 'Address already in use' 
    16:05:25 INFO: Try again to set socket... 
    16:05:25 ERROR: Failed to open socket with error 'Address already in use' 
    16:05:30 INFO: Try again to set socket... 
    16:05:30 ERROR: Failed to open socket with error 'Address already in use' 
    16:05:35 INFO: Try again to set socket... 
    16:05:35 ERROR: Failed to open socket with error 'Address already in use' 
    16:05:40 INFO: Try again to set socket... 
    16:05:40 ERROR: Failed to open socket with error 'Address already in use' 
    16:05:45 INFO: Try again to set socket... 
    16:05:45 ERROR: Failed to open socket with error 'Address already in use' 
    16:05:50 INFO: Try again to set socket... 
    16:05:50 ERROR: Failed to open socket with error 'Address already in use' 
    16:05:55 INFO: Try again to set socket... 
    16:05:55 ERROR: Failed to open socket with error 'Address already in use' 
    16:06:00 INFO: Try again to set socket... 
    16:06:00 ERROR: Failed to open socket with error 'Address already in use' 
    16:06:05 INFO: Try again to set socket... 
    16:06:05 ERROR: Failed to open socket with error 'Address already in use' 
    16:06:10 INFO: Try again to set socket... 
    16:06:11 INFO: Close socket 

Ich benutze Linux Ubuntu 14.04 und PHP 5.6.8, mit pthread kompiliert.

Antwort

0

Der Grund, warum Sie die Verbindung zum Port nicht wiederherstellen können, liegt daran, dass Ihre Verbindung nach dem Schließen des Sockets für diese Verbindung in den Zustand TIME_WAIT wechselt. Eine Möglichkeit, die Verbindung sofort schließen zu lassen, besteht darin, dass Sie diese beiden Zeilen vor Ihrer Anweisung 'socket_close ($ client)' innerhalb Ihrer Funktion 'processRequest()' hinzufügen.

$linger  = array ('l_linger' => 0, 'l_onoff' => 1); 
socket_set_option($client, SOL_SOCKET, SO_LINGER, $linger); 
+0

Ich hatte versucht, aber es hat nicht funktioniert. – Stilgar