Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

Re: How to maintain a persistent connection over sockets?

by BrowserUk (Patriarch)
on May 02, 2012 at 00:55 UTC ( [id://968348]=note: print w/replies, xml ) Need Help??


in reply to How to maintain a persistent connection over sockets?

So is there a way to keep the client connection persistent and only 'close' when the client is finished?

In general, tcp connections are persistent. That is, they only disconnect when either the client or server explicitly choose to do so. However, there is usually an 'inactivity' timeout period, often set (for historical reasons) to 900 seconds, though that can be modified at either end of the connection.

If you have reason to believe that your client might not (naturally) use the connection frequently enough to prevent the inactivity timeout from kicking, then the usual thing to do is add a 'heartbeat' message to your protocol. This takes the form of a do-nothing message or exchange, that can be initiated from either the client or the server, at some regular period less than the prevailing timeout.

And if the connection is persistent, would that prevent other clients from connecting?

That depends upon the implementation of the server.

Well written servers -- whether selecting, pre-forking or threaded -- can easily maintain concurrent, persistent connections with many clients. Hundreds or even thousands of concurrent connections are possible for low-volume protocols, but it obviously depends upon the design and implementation of the server; the volume of traffic per client; the capacity of the server hardware; and the bandwidth of the servers network connections.

But that's all very general information. To get better answers to your questions you'll need to describe your application in more detail; and outline what problems you are either experiencing or are anticipate encountering.


With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.

The start of some sanity?

  • Comment on Re: How to maintain a persistent connection over sockets?

Replies are listed 'Best First'.
Re^2: How to maintain a persistent connection over sockets?
by flexvault (Monsignor) on May 02, 2012 at 13:59 UTC

    BrowserUk,

    I use IO::Socket::UNIX for both the client and server. The routines are almost exactly the same as the perl documentation: Note: I typed this code in, so I doubt it will compile and this is just part of a lot of other code.

    Server:

    use IO::Socket::UNIX; use strict; my $server = new IO::Socket::UNIX -> new ( Local => "$ROOT/envSocket +", Type => SOCK_STREAM, Reuse => 1, Listen => 147 ); [ ... error handling ... ] while ( 1 ) { my $client = $server => accept(); if ( defined $client ) { eval { while(<$client>) { $Todo .= $_; chomp($Todo); } } if ( $@ ) { ... } if ( $Todo ) { ... process work ... } close $client; } }

    Client:

    use IO::Socket::UNIX; use strict; my $server = new IO::Socket::UNIX -> new ( Peer => "$ROOT/envSocket +", Type => SOCK_STREAM, Timeout => 10 ); [ ... error handling ... ] print $server "$Todo\n"; shutdown ( $server, 1 ); while ( <$server> ) { $answer .= $_; } shutdown ( $server, 2 ); close $server; ... }

    Even if I mistyped the code, the actual code works as expected. But the process is a lot slower than I had expected. Here are some results:

    50,000 records processed: ( results are number/second ) 1 process | client/server Writes: 2,953 | 1,152 ReadNext: 35,138 | 2,870 ReadPrev: 34,236 | 2,616

    So, if I could keep a persistent connection between the server and the client then performance may be better. Everything I have tried has just hung. Some information supplied by zentara has given me some new ideas.

    Any help will be greatly appreciated.

    Thank you

    "Well done is better than well said." - Benjamin Franklin

      I use IO::Socket::UNIX for both the client and server.

      That means I am probably the wrong person to be advising you. I don't use Unix domain sockets -- my platform doesn't have them -- and I know very little about them.

      One thought that crosses my mind that I'll say out loud without doing any further research: As far as I'm aware, unix domain sockets only work within the local box; as such they are not so different from named pipes (fifos);

      On windows, named pipes also work with the local server domain and are substantially faster than (INET) sockets.

      I typed this code in, so I doubt it will compile ...

      Unfortunately, that means it doesn't tell us anything useful.

      If you posted snippets of the real code, we might be able to spot implementation errors; even if they were not complete and runnable; but uncompilable random snippets tell us nothing.

      Here are some results: ...

      I assume, though you haven't stated it, that your concern is the lower throughput rate for inter-process comms versus intra-process comms.

      I afraid that is to be expected.

      The latter is probably implemented as a simple memory buffer within the single processes address space. As such the api's have no need to perform ring-3/ring-0/ring-3 (user space to kernel space) transitions.

      The former will be built around a process-shared memory buffer and will involve those user/kernel space transitions for every api call. In addition, they will also require kernel level locks; and may well invoke waiting for multiple task-switches until the appropriate other process -- the client or server process that is the communications partner -- to get a kernel timeslice.

      In short:inter-process comms will always carry substantially greater overheads that intra-process (inter-thread) comms. That is inevitable.

      So, if I could keep a persistent connection between the server and the client then performance may be better.

      There is nothing in the text of your description; nor the (possibly unrepresentative) code snippets you've posted that suggests you aren't already using "persistant connections". How/why do you reach the conclusion that you are using transient connections?

      In essence, what I'm suggesting here is that you are wrongly attributing "slow comms" to "a lack of persistent connections", without providing any evidence for the latter.

      I think this is one of those (relatively rare) occasions where the X/Y problem raises its head. That is, you are describing what you've wrongly concluded is the source of your problem and are asking how to fix that; rather than describing the actual symptoms that are telling you that you have a problem, and allowing us to access the possible causes.

      From your previous posts and questions I have an idea of the project you are working on; and I know you are breaking new ground in many areas concurrently. Perhaps you need to step back a little and describe the actual requirements of this part of your project and ask a more general question of teh best approach to satisfying them?


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.

      The start of some sanity?

        BrowserUk,,

        I took a while to respond. Here is working code showing what I'm trying too improve. ( I looked at the named pipes, but that seemed to imply a parent/child situation.) I used the plain socket code shown below to describe the situation. On the system I'm testing, the cost of building the socket each time more than doubles the total time of the transaction.

          ...actual requirements of this part of your project and ask a more general question of teh best approach to satisfying them?

          As usual you're right about that! My current project is to build a pure-perl NoSQL key/value database to replace Oracle's BerkeleyDB. Caching is critical to database performance, but I haven't found a 'solid' way to share the cache between processes. That was the performance numbers I showed previously ( single user vs multi-user ). Write performance is acceptable, but the read performance is not. I tried using 'send/recv', 'print/read', etc. without success. The client/server talk once and then hang!

          Any suggestions welcome!

        How to use the client/server code: Start the server first. Then one or more client(s), which will show the times for opening the connection, total time of the transaction and then the percentage of overhead.

        Server:

        use strict; use warnings; use Time::HiRes qw( gettimeofday usleep ); use Socket; my $server_port = 3000; # make the socket socket(Server, PF_INET, SOCK_STREAM, getprotobyname('tcp')); # so we can restart our server quickly setsockopt(Server, SOL_SOCKET, SO_REUSEADDR, 1); # build up my socket address my $my_addr = sockaddr_in($server_port, INADDR_ANY); bind(Server, $my_addr) or die "Couldn't bind to port $server_port: $!\n"; # establish a queue for incoming connections # print SOMAXCONN, "\n"; listen(Server, SOMAXCONN) or die "Couldn't listen on port $server_port: $!\n"; while ( 1 ) { my $WorkName = "FBServer"; my $cnt = 0; my $result = ""; while ( 1 ) { $cnt++; my $client; $0 = "$WorkName: Waiting for work!"; accept( $client, Server ); if ( defined $client ) { my $tm = substr(scalar localtime(),4,15); $0 = "$WorkName: Working ( $cnt ) $tm"; my $stime = gettimeofday; my $html = ""; my $Todo = "" +; my $size = 0; $0 = "$WorkName: Read Socket ( $cnt ) $tm"; eval { while (<$client>) { $Todo .= "$_"; chomp($Todo); } }; if ( $@ ) { my $err = $@; print $client "$err\n"; syslog('alert', "2 ERROR: $err"); last; } if ( $Todo ) { chomp($Todo); ## Debian patch print "$Todo ", sprintf("%0.8f",gettimeofday - $ +stime),"\n"; print $client "Client $Todo: Thank you!\n"; close ( $client ); }; } } } exit;
        Client:
        use strict; use warnings; use Socket; use Time::HiRes qw( gettimeofday usleep ); our @Total = (); our $Totcnt = 500; our $remote_host = "172.16.47.22"; our $remote_port = 3000; for ( 0..$Totcnt ) { my $parms = $$; my $result = Call_Multi_User( $parms ); if ( ! $result ) { print "\t****Nothing Back\n"; } print "$result\n"; usleep 20000; } my $open = $Total[0]; my $total = $Total[1]; my $diff = ( $total / $open ) - 1 ; $open = $Total[0] / $Totcnt; my $total = $Total[1] / $Totcnt; print "\n\tTotals:\t\t\t".sprintf("%0.8f",$open) . "\t".sprintf("% +0.8f",$total)."\t+ ".sprintf("%0.3f",$diff)." %\n\n"; exit; sub Call_Multi_User { my $Todo = shift; if ( ! defined $Todo ) { return( "" ); } our $server; my $stime = gettimeofday; my $answer = ""; # if ( ! $server ) ## if this worked then we wouldn't have t +he establish overhead! { socket( $server, PF_INET, SOCK_STREAM, getprotobyname('tcp +')); # create a socket # build the address of the remote machine my $internet_addr = inet_aton($remote_host) or die "Couldn't convert $remote_host into an Inte +rnet address: $!\n"; my $paddr = sockaddr_in($remote_port, $internet_addr); # connect connect($server, $paddr) or die "Couldn't connect to $remote_host:$remote_p +ort: $!\n"; select((select($server), $| = 1)[0]); # enable command bu +ffering } my $open = gettimeofday - $stime; print $server "$Todo\n"; shutdown($server,1); # my $no = 0; while (<$server>) { $answer .= $_; } close $server; chomp($answer); my $total = gettimeofday - $stime; my $diff = ( $total / $open ) - 1 ; $Total[0] += $open; $Total[1] += $total; $answer .= "\t".sprintf("%0.8f",$open) . "\t".sprintf("%0.8f", +$total)."\t+ ".sprintf("%0.3f",$diff)." %"; return ( $answer ); }
        Client output: Client 24006: Thank you! 0.00029397 0.00068903 + 1.34 +4 % Client 24006: Thank you! 0.00030303 0.00076103 + 1.51 +1 % Client 24006: Thank you! 0.00030303 0.00061202 + 1.02 +0 % Client 24006: Thank you! 0.00033212 0.00082612 + 1.48 +7 % Client 24006: Thank you! 0.00037408 0.00084996 + 1.27 +2 % Client 24006: Thank you! 0.00030398 0.00110912 + 2.64 +9 % Totals (Average): 0.00021664 0.00051245 + 1.36 +5 % Server output: ( 2 clients running ) 24006 0.00013709 24007 0.00002718 24007 0.00003099 24006 0.00002503 24007 0.00013399 24006 0.00002623 24006 0.00003099 24007 0.00002503 24006 0.00013494 24007 0.00002503 24007 0.00003099 24006 0.00002503 24007 0.00013399 24006 0.00002599

        Thank you

        "Well done is better than well said." - Benjamin Franklin

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://968348]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others lurking in the Monastery: (3)
As of 2024-04-19 21:19 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found