gpt4 book ai didi

PHP如何强制释放套接字

转载 作者:可可西里 更新时间:2023-11-01 12:57:37 26 4
gpt4 key购买 nike

我一直在尝试使用线程来管理套接字连接。然而,在我的进程/线程的执行之间,套接字没有被清理,我得到了异常:

socket_create_listen(): unable to bind to given address [98]: Address already in use in ... It will get finally cleaned after around 1 minute.

我在互联网上搜索过,但找不到解决方案。此外,如果您删除 while(1) 循环中的代码并执行两次我的 php 文件,它也会给出相同的错误。我希望所有资源都在进程退出时被清除。

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

结果:

    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

我使用 Linux Ubuntu 14.04 和 PHP 5.6.8,使用 pthread 编译。

最佳答案

您无法重新连接到该端口的原因是您的 curl 连接在您关闭该连接的套接字后进入 TIME_WAIT 状态。您可以立即关闭连接的一种方法是,如果您在 processRequest() 函数中的 socket_close($client) 语句之前添加这两行。

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

关于PHP如何强制释放套接字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31101881/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com