Re: IO::Socket *always* making connection?
by saskaqueer (Friar) on Feb 08, 2005 at 21:55 UTC
|
update: Oops, I wasn't thinking either. My eval/alarm solution will not work because the connection is successfull and therefore it contains the exact same issue as the OP. Sorry. *sigh*
In lieu of the completely refactored parent node, here is the refactored answer :)
When you set a socket to listen() via IO::Socket::INET, the port will come up as in-use and will queue up successive connection requests. Since your first client that connects is in an infinite loop, the second client to connect is simply waiting for the first client to close the connection to the server.
The easiest way to fix such a problem is to set a timeout via a signal handler. Such an example is provided here (see the last paragraph of screen 7 of `perldoc perlipc` on a 24-row terminal for an explanation of the $SIG{ALRM} and alarm()):
#!/usr/bin/perl
# c.pl
use strict;
use warnings;
use IO::Socket;
use less 'java'; #;-)
my $b_address = '127.0.0.1'; #IP of box A
my $b_port = '8888'; #Port number guipartner set to on A
my $eol = "\015\012"; #sets end of line chracters for socket transmi
+ssions
my $skipC = 0;
my $socketC;
eval {
# set the signal handler. we die when the signal hits us
local $SIG{ALRM} = sub { die("timeout\n") };
alarm(5); # number of seconds for timeout
$socketC = new IO::Socket::INET (
PeerAddr => $b_address,
PeerPort => $b_port,
Proto => 'tcp',
);
alarm(0); # cancel the alarm signal
};
# we got the alarm signal, so we timed out
if ($@ eq "timeout\n") {
print "socket not available\n";
exit;
}
# some other unexpected error
elsif ($@) {
die($@);
}
local $/=$eol; #set default EOL to $eol so chomp works
while (!$skipC) {
print $socketC "c.pl sends \$skipC=$skipC", $eol;
print "message sent\n";
sleep 2;
}
print "socket not available\n";
close $socketC;
Also, you can modify your server code (b.pl) so that you're not recreating the socket for each connection. You can instead move the socket creation outside of the infinite loop and loop on accept():
#!/usr/bin/perl
# b.pl
use strict;
use warnings;
use IO::Socket;
use less 'java'; #;-)
my $eol = "\015\012"; #sets end of line chracters for socket transm
+issions
my $sock = new IO::Socket::INET (
LocalPort => '8888',
Proto => 'tcp',
Listen => 1,
) or die "Could not create socket: $!\n";
while ( my $newsock = $sock->accept() ){ #continuous loop: wait
+ for socket connections until end of time
while (my $incoming = <$newsock>){
local $/=$eol; #set default EOL to $eol so chomp wo
+rks
chomp($incoming);
print "received: $incoming\n";
}
close $newsock;
close $sock;
}
| [reply] [d/l] [select] |
|
|
Did you test this code? Because it is not working on my system. In fact, it's a step backwards... The original code for A and C would die gracefully ("couldn't send message to connected socket") if I killed B, and with your revised code for A/C, they both keep merrily sending messages. I also tried your fix for B, but it behaves the same way as my original B. :-(
edit: I'm guessing this code is non-functional for the same reason mine is... C *thinks* it is making this connection, even though B proceeds to ignore everything it says. So you set alarm(5), you make the fake connection, and you set alarm(0). The crux of the problem is (and always has been), "why does C think it has the connection?"
--
Linux, sci-fi, and Nat Torkington, all at Penguicon 3.0
perl -e 'print(map(chr,(0x4a,0x41,0x50,0x48,0xa)))'
| [reply] [d/l] |
Re: IO::Socket *always* making connection?
by dragonchild (Archbishop) on Feb 08, 2005 at 18:18 UTC
|
IO::Socket::INET doesn't die if the connection isn't made. So, $@ wouldn't be set, even if you're in an eval. Maybe you should check to see if $socketA is defined or not ...
Being right, does not endow the right to be rude; politeness costs nothing. Being unknowing, is not the same as being stupid. Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence. Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.
| [reply] |
|
|
Thanks for the reply. That was a good tip about eval (which I never used before), but that didn't solve my problem. I've rewritten the original post to try to be clearer, as well as getting rid of the evals.
--
Linux, sci-fi, and Nat Torkington, all at Penguicon 3.0
perl -e 'print(map(chr,(0x4a,0x41,0x50,0x48,0xa)))'
| [reply] [d/l] [select] |
Re: IO::Socket *always* making connection?
by nobull (Friar) on Feb 08, 2005 at 18:18 UTC
|
IO::Socket does not indicate a failure by thowing an exception is does so by returning false.
In general most Perl modules/function indicate what you could consider soft falures (file does not exist, port in use, anything from outside of Perl) by returning a special return value rather than throwing an exception.
Exceptions are mostly only thrown when the arguments passed in are invalid.
These rules are not hard and fast - module authors can choose differently. | [reply] |
|
|
| [reply] [d/l] |
Re: IO::Socket *always* making connection?
by saskaqueer (Friar) on Feb 08, 2005 at 18:32 UTC
|
As such (such being that IO::Socket::INET does not die or set $@ on failure), you'd want one of the following code snippets:
# best solution:
$socketA = new IO::Socket::INET(
PeerAddr => $A_box_address,
PeerPort => $A_box_port,
Proto => 'tcp',
) or $skipA = 1;
# another option:
$socketA = new IO::Socket::INET(
PeerAddr => $A_box_address,
PeerPort => $A_box_port,
Proto => 'tcp',
);
$skipA = 1 unless defined($socketA);
# yet another
eval q{
$socketA = new IO::Socket::INET(
PeerAddr => $A_box_address,
PeerPort => $A_box_port,
Proto => 'tcp',
) or die("ouch\n");
};
$skipA = 1 if ($@ eq "ouch\n");
# and still yet...
eval q{
$socketA = new IO::Socket::INET (
PeerAddr => $A_box_address,
PeerPort => $A_box_port,
Proto => 'tcp',
) or die("ouch\n");
} or $skipA = 1;
| [reply] [d/l] |
|
|
As such (such being that IO::Socket::INET does not die or set $@ on failure), you'd want one of the following code snippets:
# best solution:
$socketA = new IO::Socket::INET(
PeerAddr => $A_box_address,
PeerPort => $A_box_port,
Proto => 'tcp',
) or $skipA = 1;
That is exactly how my code used to look prior to encountering this problem. I thought that eval might help me catch it, but obviously no... Everybody seems to think eval is my problem now... With the code looking exactly as above, I still do not see $skipA == 1 unless I kill the program at the PeerPort. If it is simply busy with another client, $skipA stays == 0.
--
Linux, sci-fi, and Nat Torkington, all at Penguicon 3.0
perl -e 'print(map(chr,(0x4a,0x41,0x50,0x48,0xa)))'
| [reply] [d/l] [select] |
|
|
I don't see where your problem is. The following script works fine for me. My box has an smpt server listening on port 25, a pop3 server on port 110, and nothing on ports 9805 and 9806. The results are as expected.
#!/usr/bin/perl -w
use strict;
use IO::Socket;
for my $port (25, 9805, 9806, 110) {
my $skipA = 0;
my $socketA = new IO::Socket::INET(
PeerAddr => 'localhost',
PeerPort => $port,
Proto => 'tcp',
) or $skipA = 1;
print "\$port: $port; \$skipA: $skipA\n";
}
__END__
$port: 25; $skipA: 0
$port: 9805; $skipA: 1
$port: 9806; $skipA: 1
$port: 110; $skipA: 0
| [reply] [d/l] |
|
|
A reply falls below the community's threshold of quality. You may see it by logging in.
|