Edit report at https://bugs.php.net/bug.php?id=71251&edit=1
ID: 71251
User updated by: gohanman at gmail dot com
Reported by: gohanman at gmail dot com
Summary: Blocking TCP socket connection does not timeout
Status: Not a bug
Type: Bug
Package: Sockets related
Operating System: Windows 10
PHP Version: 7.0.1
Block user comment: N
Private report: N
New Comment:
I bumped into this again today and the behavior still seems slightly odd. Having recently run into a
similar issue with PDO using mysqlnd I though that the ini setting for default_socket_timeout would
apply here. It doesn't seem to.
As krakjoe noted, all of this only applies when the host you're connecting to is silently
dropping packets to a closed port rather than actively rejecting them.
// This times out after a second
ini_set('default_socket_timeout', 1);
$fp = stream_socket_client('tcp://localhost:15674', $errno, $error);
// This does not
ini_set('default_socket_timeout', 1);
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_block($sock);
$test = socket_connect($sock,'localhost',15674);
The documentation does rightly note that default_socket_timeout applies to "socket based
streams" but given the name of the setting it's at the very least unintuitive that it
doesn't also apply to actual sockets.
Previous Comments:
------------------------------------------------------------------------
[2016-05-07 07:25:34] krakjoe@php.net
Forgot to change status ...
------------------------------------------------------------------------
[2016-05-07 07:23:53] krakjoe@php.net
There is no bug here.
The difference in behaviour you see is due to the way the machine at the other end deals with the
attempt to connect. "localhost" would hopefully drop the connection - actively refuse it,
while some other host (say google.com for example) will not.
Setting send/recv timeout doesn't work for connect - you are neither reading nor writing, but
awaiting readiness (for reading and writing) ...
Here's one way of performing a socket_connect() with a reliable timeout:
<?php
function socket_create_connect($domain, $type, $protocol, $host, $port, $timeout) {
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if (!$sock) {
$errno = socket_last_error();
throw new \RuntimeException(
socket_strerror($errno), $errno);
}
socket_set_nonblock($sock);
if (!socket_connect($sock, $host, $port)) {
switch ($errno = socket_last_error()) {
case SOCKET_EINPROGRESS:
if (!socket_select($read, $write = [$sock], $except = [], $timeout, 0)) {
throw new \RuntimeException(
socket_strerror($errno), $errno);
}
break;
default:
throw new \RuntimeException(
socket_strerror($errno), $errno);
}
}
socket_set_block($sock);
return $sock;
}
$sock = socket_create_connect(AF_INET, SOCK_STREAM, SOL_TCP, "google.com", 15674, 3);
socket_close($sock);
echo "Done";
------------------------------------------------------------------------
[2016-01-03 17:58:09] ab@php.net
Seems I'm not reproducing it with 7.0, neither with Apache nor with CLI on win10 build
10586.36. It could be something in your environment or ini, still need that info to start to debug.
Lets see whether you could dig down to it, or maybe someone else has more luck with reproducing.
Thanks.
------------------------------------------------------------------------
[2016-01-01 18:15:55] gohanman at gmail dot com
There's nothing on localhost:15674. The connection should be refused. When I run it (in Windows
10 via Apache 2.4, using mod_php) it does not print "Done". It blocks on the
socket_connect line seemingly forever - at least an hour.
That's the bug I'm trying to report. socket_connect to a non-existent end point with a
blocking socket is blocking indefinitely rather than timing out.
Using PHP5.6 (on the same Windows 10 machine via Apache 2.4, using mod_php) it *does* print
"Done" after about a second. So at least in this specific configuration the behavior seems
to have changed from 5.6 to 7.0.
------------------------------------------------------------------------
[2016-01-01 17:20:27] ab@php.net
Thanks for the report. I've a question - what is localhost:15674 supposed to have behind? On my
machine there's no such service, so I just see "Done" with your repro code - the
connection simply gets refused. If there's some difference in 7.0, it therefore should depend
and be reproducable on a concrete counterpart. Could you please provide more info on that?
Thanks.
------------------------------------------------------------------------
The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at
https://bugs.php.net/bug.php?id=71251
--
Edit this bug report at https://bugs.php.net/bug.php?id=71251&edit=1