php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #17083 socket_select is closing still-needed sockets
Submitted: 2002-05-07 18:51 UTC Modified: 2002-05-09 16:31 UTC
From: trobinson at gksystems dot com Assigned:
Status: Closed Package: Sockets related
PHP Version: 4.2.0 OS: RH 7.1
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: trobinson at gksystems dot com
New email:
PHP Version: OS:

 

 [2002-05-07 18:51 UTC] trobinson at gksystems dot com
The script below listens on 10 ports from 26001 to 26010.
On return from socket_select, all sockets have stopped listening except
the one on which there is action, plus 26010.
This is wrong. All 10 sockets should still be listening.
strace reveals that close() is being called on the other sockets.
I suspect this is because the garbage collector does not detect
that the $listen_sockets and $r arrays are different, because for efficiency it does not actually make a copy until one of the arrays is modified.  When the old value of $r is discarded to make way for the results from select(), 
the engine detects that the use counts on most of the socket resource objects have gone to zero.
The two exceptions are the socket that woke up select(), and the 10th created socket still stored in $sock.
To test this, I added $sockcopy as yet another copy of all the sockets. The problem persisted.
Next, I added an additional junk value to $sockcopy to force the
engine to make a separate internal copy, instead of keeping just a reference.
That fixed the problem.

...Tom Robinson

#!/usr/local/bin/php -q
<?php
ob_implicit_flush ();
for ($i = 1; $i <= 10 ; ++$i){
($sock = socket_create(AF_INET, SOCK_STREAM, 0)) or die ("socket $i");
socket_setopt($sock, SOL_SOCKET, SO_REUSEADDR, 1);
($b= socket_bind($sock, '0.0.0.0', 26000+$i)) or die("bind $i");
($l= socket_listen($sock, 4)) or die ("listen $i");
socket_set_nonblock($sock);
$listen_sockets[$i] = $sock;
}
$sockcopy = $listen_sockets;              // for speed, engine makes just a reference until one of them changes
//$sockcopy["end"] = "more stuff";  // so engine makes a copy right now
$r = $listen_sockets;
echo '
To see the 10 listening sockets:   netstat -a | grep 260
Then connect to one of the ports:  telnet localhost 26005
This will cause select to return. Repeat the netstat - only 2 sockets listening now!
Then repeat the procedure, un-commenting the //$sockcopy["end"] line.
Waiting on select()...';
$x = socket_select($r, $w = null, $e = null, null);
echo "\n";
echo "select r: ", count($r), "  w: ", count($w), "  e: ", count($e), "\n";
echo "Sleep 30 s before exiting..."; sleep(30); echo "\n";
exit();
?>

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2002-05-09 16:31 UTC] jason@php.net
This is a known issue that will be fixed in 4.2.1, if you need to work around it use the latest snapshot.

-Jason
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Mar 29 14:01:28 2024 UTC