Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scalar value errors (with IO::Socket)

Tags:

perl

This is my current code:

#!/usr/bin/perl -w

use strict;
require IO::Socket;

while (<>) {
        chomp(my $host = $_);
        my @header;

        print "Connecting to: $host\n";
        my $socket = new IO::Socket::INET(
                PeerAddr => $host,
                PeerPort => 80,
                Proto => 'tcp') || print "Could not connect: $!\n";

        print "Connected.\n";

        print $socket "GET / HTTP/1.0\n\n";
        my $i = 0;
        while (<$socket>) {
                @header[$i] = $_;
                $i++;
        }

        $i = 0;
        print "--------------------------------------\n";
        while ($i <= 8) {
                print "@header[$i++]";
        }

        print "-------------------------------------\n";
        print "Finished $host\n\n";
}

If while going through a list of IP's, and a host is down, instead of continuing onto the next IP, it will give me an error "Can't use string ("1") as a symbol ref while "strict refs" in use".

If I then change @header[$i] = $; to $header[$i] = $; I also get the same error. How can I make this script better.

like image 992
Daveid Fred Avatar asked Dec 27 '22 06:12

Daveid Fred


1 Answers

The problem is in the way you set $socket:

my $socket = new IO::Socket::INET(
        PeerAddr => $host,
        PeerPort => 80,
        Proto => 'tcp') || print "Could not connect: $!\n";

Since you're using the || operator, which has higher precedence than =, this statement is parsed as

my $socket = (new IO::Socket::INET(...) || print ...);

If new IO::Socket::INET returns a false value (as it does if the connection fails), the print will be executed and its return value (which is normally 1) will be assigned to $socket. When you then try to use $socket as an indirect object in the statement:

print $socket "GET / HTTP/1.0\n\n";

Perl notices that the value 1 is not actually an object reference and throws the error you reported.

If you'd used the low-precedence operator or instead of ||, the value of $socket would've been undef instead of 1, and the error message you'd have received would've been something like Can't use an undefined value as a symbol reference .... Of course, this wouldn't have actually fixed your problem, but at least it might've made it easier to diagnose.

To actually fix the problem, you need to fix your code so that you won't keep executing the rest of the loop body if the connection fails. One way to do that would be like this:

my $socket = new IO::Socket::INET(
        PeerAddr => $host,
        PeerPort => 80,
        Proto => 'tcp');

unless ($socket) {
        print "Could not connect: $!\n";
        next;  # skip the rest of the loop
}
like image 124
Ilmari Karonen Avatar answered Jan 11 '23 00:01

Ilmari Karonen