Changeset 24838 for gs2-extensions
- Timestamp:
- 2011-12-01T12:22:04+13:00 (12 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
gs2-extensions/parallel-building/trunk/src/perllib/SocketsSwimmingThreadPoolClient.pm
r24685 r24838 9 9 use strict; 10 10 use warnings; 11 12 my $retry_time = 30; 11 13 12 14 sub new … … 23 25 } 24 26 27 sub open_socket 28 { 29 my $self = shift @_; 30 # There is, unfortunately, a complication when using TCP sockets - that being 31 # the amount of time sockets linger after being closed. This TIME_WAIT period 32 # is required to ensure the terminating ACKs (kernel level) are recieved (in 33 # a graceful disconnect) and to allow time for 'wandering duplicates' to 34 # finally arrive. While there are (platform/OS/hardware) methods for getting 35 # rid of / shortening this grace period they aren't recommended (for both 36 # stability and security reasons). 37 # Thus you have the issue that, very occasionally and somewhat based upon the 38 # current turnover rate of TCP connections, you may exhaust the available 39 # pool of TCP sockets (as the rest are stuck waiting on TIME_WAIT timeouts). 40 # While the 'reuse' flag might lead you to expect the ability to 'reuse' the 41 # socket - there is one glaring caveat: you can't reuse the port from the 42 # same origin address as this would be a major security flaw. So in reality 43 # the reuse flag does nothing for us (which is why I removed it). 44 # Instead I am forced to put the socket connection in a loop and, if the 45 # first attempt to create the socket fails, wait around for SO_LINGER time 46 # in the hope that the TCP socket pool will have finally purged a number of 47 # the stranded TIME_WAIT connections. 48 # One last kick in the daddy-bags - the *default* SO_LINGER is set to 2*MSL 49 # (Maximum Segment Lifetime - the 'Time To Live of TCP' packets). This means 50 # (according to RFC793) we may be waiting up to 4 minutes for TIME_WAITs to 51 # be reaped. Sigh. Still - ever an optimist - I'll retry the socket 52 # connection every 30 seconds. 53 # References: 54 # http://www.perlmonks.org/?node_id=771242 55 # http://hea-www.harvard.edu/~fine/Tech/addrinuse.html 56 # http://blog.port80software.com/2004/12/07/hurry-up-and-time_wait/ 57 # http://www.isi.edu/touch/pubs/infocomm99/infocomm99-web/ 58 # http://www.faqs.org/rfcs/rfc793.html 59 while(1) 60 { 61 my $socket= new IO::Socket::INET(PeerAddr => $self->{host} || 'localhost', 62 PeerPort => $self->{port} || 8190, 63 Proto => 'tcp'); 64 if ($socket) 65 { 66 return $socket; 67 } 68 print "Failed to create client socket: $!\n"; 69 print "=> Most likely cause - TCP ephemeral ports exhausted (stuck in TIME_WAITs)\n"; 70 print "=> Retry in " . $retry_time . " seconds.\n"; 71 } 72 } 73 25 74 sub query 26 75 { 27 76 my ($self, $query)= @_; 28 my $socket= new IO::Socket::INET(PeerAddr => $self->{host} || 'localhost', 29 PeerPort => $self->{port} || 8191, 30 Proto => 'tcp'); 31 croak "$!. Is the server running?\n" unless $socket; 77 my $socket = $self->open_socket(); 78 croak "Fatal Error! $!\nDetails: " . $self->{'host'} . ":" . $self->{'port'} . "\n" unless $socket; 32 79 binmode($socket, ":utf8"); 33 80 print $socket $query . "\n.\n"; … … 39 86 last if $reply =~ s/\n\.\n$//; 40 87 } 41 $socket->shutdown(2);88 close($socket); 42 89 return $reply; 43 90 }
Note:
See TracChangeset
for help on using the changeset viewer.