How to catch the error without exiting from the script? - perl

The below script exit when the peer port is not listening. I don't want it to exist instead it needs to keep trying. I know 'die' below will cause this, but is there a better way to capture the error without exiting.
my $socket = new IO::Socket::INET (
PeerHost => $properties{peer_host},
PeerPort => $properties{peer_port},
Proto => 'tcp',
);
die "cannot connect to the server $!\n" unless $socket;
while(1){
#send something to the port
}
Output:
cannot connect to the server Connection refused

Alternatives to die might be helpful: http://perldoc.perl.org/Carp.html
and warn:
http://perldoc.perl.org/functions/warn.html

you can use warn
my $socket = new IO::Socket::INET (
PeerHost => $properties{peer_host},
PeerPort => $properties{peer_port},
Proto => 'tcp',
);
warn "cannot connect to the server $#\n" unless $socket;
while(1){
#send something to the port
}

Related

perl socket: increment port if in use

I have the following code:
use IO::Socket::INET;
use Sys::Hostname;
use Socket;
my($addr)=inet_ntoa((gethostbyname(hostname))[4]);
my $port_to_use = 7777;
my $socket = new IO::Socket::INET (
LocalHost => $addr,
LocalPort => $port_to_use,
Proto => 'tcp',
Listen => 5,
Reuse => 1
);
die "cannot create socket $!\n" unless $socket;
my $client_socket = $socket->accept();
if i start this in one screen and start another one in the other screen, i get an error:
cannot create socket Address already in use
instead of dying, i would like to try using different port (increment by 1) until it can find the one to use.
I've try to convert the die line with eval but im not able to catch it
any suggestions?
Use a Loop:
use IO::Socket::INET;
use Sys::Hostname;
use Socket;
my($addr)=inet_ntoa((gethostbyname(hostname))[4]);
my $port_to_use = 7776;
my $fail =1;
my $socket;
while ($fail == 1){
$port_to_use++;
$fail = 0;
warn $port_to_use;
$socket = IO::Socket::INET->new (
LocalHost => $addr,
LocalPort => $port_to_use,
Proto => 'tcp',
Listen => 5,
Reuse => 0
) or $fail =1;
}
warn $socket->accept();
Here is a tidier alternative which actually checks to make sure the failure to bind to a given port was due to the port being in use. It also limits the port range to check. If you use the code in the other answer, and, if for some reason, the machine is not allowing your application to bind to any ports, you are going to get stuck in an infinite loop. It may also cause your application to bind to ports that should otherwise have been left alone etc.
#!/usr/bin/env perl
use strict;
use warnings;
use Carp qw( croak );
use Errno qw( EADDRINUSE );
use IO::Socket::INET;
use Sys::Hostname qw( hostname );
use Socket;
# These can come from a config file or command line
# See also https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers#Dynamic.2C_private_or_ephemeral_ports
# https://unix.stackexchange.com/a/39784/2371
my #port_range = (0xC000, 0xFFFF);
my $addr = inet_ntoa( (gethostbyname(hostname) )[4]);
my $socket;
TRY_PORT:
for my $port ($port_range[0] .. $port_range[1]) {
warn "Trying port $port\n";
$socket = IO::Socket::INET->new(
LocalHost => $addr,
LocalPort => $port,
Proto => 'tcp',
Listen => 7,
Reuse => 0,
);
if ($socket) {
warn "Bound to port $port\n";
last TRY_PORT;
}
if ( EADDRINUSE != $! ) {
croak "Cannot bind to port '$port': $!";
}
warn "Port in use, trying the next one\n";
}
$socket->accept
or croak "...";
# ...

Check if UDP port is opened in Perl

I need to check if remote UDP port is opened. My part of code is:
sub scanUDP {
my $address = shift;
my $port = shift;
my $udpSocket = new IO::Socket::INET (
PeerAddr => $address,
PeerPort => $port,
Proto => 'udp',
) or return 0;
$udpSocket -> send ('hello', 0);
#........SOME CODE.............
return 1;
}
..SOME CODE.. should check if I received ICMP packets "Host unreached" or "Port unreached" to check if port is opened. But how can I do it?
Generally you can't. UDP does not have a connected state, so it is in no way required to send you any reply to the packet you sent. And that's even when ignoring package loss. You may get a positive reply if you sent a valid request in whatever protocol you're accessing and the remote port is open, but the absence of such a reply can not be used to make any conclusions.
If you really get an ICMP unreachable back you will receive the error with a later send call (unless you peer is localhost, than you might get it with the first one already). But there is no guarantee that you will get an ICMP unreachable back at all, because either ICMP or the UDP itself might be filtered by a firewall.
It looks like it will not report the problem on windows this way, but you can use recv there instead of send (works on UNIX too). The error code is probably something specific to windows, ECONNREFUSED works only on UNIX:
use strict;
use warnings;
use IO::Socket::INET;
my $cl = IO::Socket::INET->new(
PeerAddr => '192.168.122.42:12345', # definitly rejecting
Proto => 'udp',
);
$cl->send('foo') or die "send failed: $!"; # first send will succeed
# wait some time to receive ICMP unreachable
sleep(1);
$cl->blocking(0);
if ( ! $cl->recv( my $buf,0)) {
# will get ECONNREFUSED on UNIX, on Win the code is different
warn "error $!" if ! $!{EAGAIN};
}
This is the code that works for me:
sub scanUDP {
my $address = shift;
my $port = shift;
my $socket = new IO::Socket::INET (
PeerAddr => $address,
PeerPort => $port,
Proto => 'udp',
) or return 0;
$socket -> send('Hello',0);
my $select = new IO::Select();
$select -> add($socket);
my #socket = $select -> can_read(1);
if (#socket == 1) {
$socket -> recv(my $temp, 1, 0) or return 0;
return 1;
}
return 1;
}

Error in perl chat server

I'm trying to create a chat server using sockets in Perl. However, when I run the Server program I get the error:
"ERROR:(9)(Bad file descriptor)(6)(+The handle is invalid) at Server.pl line 21."
and when I run the client program I get the error:
"Cannot create the socket: No connection could be made because the target machine
actively refused it."
Here is the Server program:
#!usr/bin/perl
#server.pl
use IO::Socket;
$| = 1;
print "Server Program\n";
my $lp = 12000;
my $server_socket, $new_client, $addr, $port;
$server_socket = new IO::Socket::INET (
LocalHost => '127.0.0.1',
LocalPort => $lp,
Proto => 'tcp',
Reuse => 1) or die "Cannot create the socket: $!\n";
print "Server started at port $lp \n";
while (1) {
$new_client = $server_socket->accept() or die sprintf "ERROR:(%d)(%s)(%d)(+%s)", $!,$!,$^E,$^E;
$addr = $new_client->peerhost();
$port = $new_client->peerport();
print "Connected to client at $addr at port $port ";
while(<$new_client>) {
print "Following is the text entered by client: \n";
print "$_";
}
print "Client now disconnecting..\n";
close $new_client;
}
$server_socker->close();
And here is the client:
#!usr/bin/perl
#client.pl
use IO::Socket;
$| = 1;
print "Client Program\n";
my $lp = 12000;
my $client_socket = new IO::Socket::INET (
PeerHost => '127.0.0.1',
PeerPort => $lp,
Proto => 'tcp',
Reuse => 1) or die "Cannot create the socket: $!\n";
print "Server connected at port $lp \n";
print "Enter the text to sent to the server: \n";
$user_input = <>;
chomp $user_input;
print $plient_socket;
$client_socket->send($user_input);
$client_socket->close();
I am new to this and I'm not getting where I'm going wrong. Could anybody help?
You trying to accept a connection from a socket that's not listening. Add
Listen => SOMAXCONN,
And now for off-topic comments about your code:
Always use use strict; use warnings;. It will highlight some other problems with your code.
It doesn't make any sense to relative paths on the shebang line. You're missing a /.
On the style front, it's considered bad form to declare variables ahead of where they are used. The whole point of declaring variables is to limit their scope, so declaring them at the top of the program defies the purpose.
LocalHost => '127.0.0.1' (better written as LocalHost => INADDR_LOOPBACK) makes it so you can only receive connections from 127.0.0.1. That can be useful, but I don't know if you did that intentionally. The default, INADDR_ANY, allows connections from any interface.

problem with IO::Socket TCP connection

I am trying to write a simple IO::Socket connection in perl. However, I am running into some problems. Here is the code on the server side:
my $listener =
IO::Socket::INET->new( LocalPort => 8000, Listen => 1, Reuse => 1 );
die "Can't create socket for listening: $!" unless $listener;
print "Listening for connections on port 8000\n";
while(1) {
while ($client = $listener->accept()) {
while ( <$client>) {
my #arguments = split(/ /, $_ );
my $result = "something" ;# here we do something in my code
warn $result;
print $client $result;
close $client;
}
}
}
And the client code:
use IO::Socket;
my $sock = new IO::Socket::INET (
PeerAddr => 'xx.xxx.xxx.xxx',
PeerPort => '8000',
Proto => 'tcp',
);
die "Could not create socket: $!\n" unless $sock;
$sock->autoflush(1);
print $sock "somethin something";
print "sent\n";
while ( <$sock> ) { print }
close $sock;
My problem now is that the data seems to be only sent from the client to teh sever when I close the client Perl program. I get the "sent" message on the client side, but the "something" message on the server side does not appear until after I have manually closed the client side.
Also, I want to get the server response. Thus far, since I have to close the script manually, the response does not et to the client side.
Can anyone help?
while ( <$sock> ) -- waits for a line. That is for a string, ended by "\n" character.
You must add "\n" to strings, or use 'read' function instead.

How can I specify which port to use in Perl's IO::Socket::INET?

I am using IO::Socket::INET to create inter-process communication in my program. I need to use a specific port number in my TCP client. I was following the example in Perl doc, but it doesn't work. Here is my code:
old code(working):
tx_socket = new IO::Socket::INET->new('127.0.0.1:8001') || die "Can't connect to 127.0.0.1:8001 : $!\n";
new code(not working):
tx_socket = new IO::Socket::INET->new('127.0.0.1:8001', LocalPort=>9000 ) || die "Can't connect to 127.0.0.1:8001 : $!\n";
Does anyone know what's wrong?
Grant McLean's answer works, if you fix the missing comma, but "works" here may be relative to what you are expecting.
use IO::Socket::INET;
$sock = IO::Socket::INET->new(
PeerAddr => '127.0.0.1',
PeerPort => 8001,
LocalPort => 9000,
Proto => 'tcp'
);
die("No socket!\n") unless $sock;
print "Socket good!\n";
Running this yields:
No socket!
Which isn't because the code doesn't work, it's working as expected (in my case). That is, it's expected that a connection to a localhost port 8001 will fail with nothing listening on the other side. This illustrates the usefulness of error reporting:
use IO::Socket::INET;
$sock = IO::Socket::INET->new(
PeerAddr => '127.0.0.1',
PeerPort => 8001,
LocalPort => 9000,
Proto => 'tcp'
) or die("$!\n");
die("No socket!\n") unless $sock;
print "Socket good!\n";
Which running now yields:
Connection refused
If I run netcat listening on port 8001, I get a different result:
Socket good!
According to the documentation, you should be doing something like:
$sock = IO::Socket::INET->new(
PeerAddr => '127.0.0.1',
PeerPort => 8001,
LocalPort => 9000,
Proto => 'tcp'
) or die "Connect error: $!";