2015-06-28 22 views
6

Ho cercato di utilizzare una discussione per gestire la connessione socket. Tuttavia tra le esecuzioni del mio processo/thread, la presa non vengono pulite e ottengo l'eccezione:PHP come forzare la presa di corrente

socket_create_listen(): in grado di legarsi al dato indirizzo [98]: Indirizzo già in uso in .. Sarà pulito definitivamente dopo circa 1 minuto.

Ho cercato su Internet, ma non sono riuscito a trovare una soluzione. Inoltre, se rimuovi il codice nel ciclo while (1) ed esegui due volte il mio file php, verrà restituito lo stesso errore. Mi sarei aspettato che tutte le risorse fossero pulite con l'uscita del processo.

<?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"; 
    } 
} 
?> 

Risultato:

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 

io uso Linux Ubuntu 14.04 e PHP 5.6.8, compilato con pthread.

risposta

0

Il motivo per cui non è possibile riconnettersi alla porta è perché la connessione dell'arricciamento passa a uno stato TIME_WAIT dopo aver chiuso il socket per quella connessione. Un modo per chiudere immediatamente la connessione è se aggiungi queste due righe prima dell'istruzione socket_close ($ client), all'interno della tua funzione processRequest().

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

Avevo provato, ma non ha funzionato. – Stilgar

Problemi correlati