8

I am wanting to use PHP to create a persistent socket connection to a notification service server and I am wondering how many Apache/PHP threads would be able to concurrently use the socket before I have problems. I have done some testing with this but I cannot seem to produce any problems.


Edit

I am using the socket like this:

$fh = pfsockopen('127.0.0.1', '1338');
fwrite($fh,$data);

Every PHP thread would share the same persistent socket

6
  • Could you provide a code example to help me imagine what you do? Commented Jan 10, 2013 at 22:04
  • You can create as many as your bandwidth/memory would allow, I assume... Commented Jan 10, 2013 at 22:06
  • How are you sharing the socket between threads? pthreads? Commented Jan 10, 2013 at 22:14
  • I added more details about how I am using it. Commented Jan 10, 2013 at 22:17
  • That's the first time I see this function. Could you link the documentation for this? Commented Jan 11, 2013 at 0:38

1 Answer 1

26

The limitation with fsockopen is the maximum amount of open file descriptors defined in the systems kernel settings. If pfsockopen is implemented well, it should only use one single socket connection, means only one file descriptor per php process.

You'll have to test this.

e.g.

$fd = pfsockopen('173.194.44.24', 80);
echo $fd;

This will output the id of the file descriptor: Resource id #1

Open this in a web browser and reload the page several times - you should see the same id each time you are using the same socket connection.

In a default Apache prefork MPM - mod_php setup you probably are randomly sent to different forked processes which will most likely result in n different ids cycling through, while n depends on your Apache configuration of

  • MinSpareServers (<= n pConnections)
  • MaxSpareServers (>= n pConnections)
  • MaxRequestsPerChild (tMax)

When you reach MaxRequestsPerChild the process is terminated and the persistent connection on this child as well.

In a Apache Worker MPM or any other fastcgi-capable webserver like Lighttpd or Nginx combined with PHP-FPM or PHP-cgi + fastcgi I am expecting the same behavior, now not caused by the webserver but by the php processes.

In parallel to the apache settings described above, the relevant settings are

PHP-FPM

  • pm.min_spare_servers (<= n pConnections)
  • pm.max_spare_servers (>= n pConnections)
  • pm.max_requests (tMax)

FastCGI

  • PHP_FCGI_CHILDREN (= n pConnections)
  • PHP_FCGI_MAX_REQUESTS (tMax)

In all configurations the maximum lifetime of a persistent connection is (in amount of requests handled by that process) tMax, the max amount of parallel persistent connections n pConnections

Simulating this on the command-line (php-cli)

# php -a
Interactive shell                            # in a webserver environment this is the equivalent of one child

php > $fd1 = fsockopen( 'google.de', 80 );   # open non-persistent connection
php > echo $fd1 . "\n";
Resource id #1
php > $fd2 = fsockopen( 'google.de', 80 );   # open another one
php > echo $fd2 . "\n";
Resource id #2                               # new fd, new connection

php > $pd1 = pfsockopen( 'google.de', 80 );  # persistent connection
php > echo $pd1 . "\n";
Resource id #3                               # first persistent fd
php > $pd2 = pfsockopen( 'google.de', 80 );
php > echo $pd2 . "\n";                        
Resource id #3                               # uses the same connection

php > exit                                   # simulating MaxRequestsPerChild threshold
# php -a
Interactive shell

php > $pd3 = pfsockopen( 'google.de', 80 );  # persistent connection, same host
php > echo $pd3 . "\n";
Resource id #1                               # resource id reused because all old connections are gone

EDIT

Acually I forgot to mention a second limitation. Connections of course can be closed anytime by the server itself. This heavily depends on the server settings and protocol you are using.

Most servers close a connection after n seconds of silence and after x seconds of total connection time.

pfsockopen handles this silently, it simply opens a new connection when the old one is gone.

Simulating this on cli again:

# php -a
Interactive shell

php > $pd1 = pfsockopen( '127.0.0.1', 80 );
php > echo $pd1 . "\n";
Resource id #1
php > $pd1 = pfsockopen( '127.0.0.1', 80 );
php > echo $pd1 . "\n";
Resource id #1

(restarting my webserver on the another console /etc/init.d/nginx restart)

php > $pd1 = pfsockopen( '127.0.0.1', 80 );
php > echo $pd1 . "\n";
Resource id #2
Sign up to request clarification or add additional context in comments.

1 Comment

Wow, this was a very thorough and well-formatted explanation. I was hoping that the answer would be basically that but I was unsure of my testing results. Thank you!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.