Recipe 17.1 Writing a TCP Client

17.1.1 Problem

You want to connect to a socket on a remote machine.

17.1.2 Solution

This solution assumes you're using the Internet to communicate. For TCP-like communication within a single machine, see Recipe 17.6.

Either use the standard IO::Socket::INET class:

use IO::Socket;

$socket = IO::Socket::INET->new(PeerAddr => $remote_host,
                                PeerPort => $remote_port,
                                Proto    => "tcp",
                                Type     => SOCK_STREAM)
    or die "Couldn't connect to $remote_host:$remote_port : $@\n";

# ... do something with the socket
print $socket "Why don't you call me anymore?\n";

$answer = <$socket>;

# and terminate the connection when we're done
close($socket);

or create a socket by hand for better control:

use Socket;

# create a socket
socket(TO_SERVER, PF_INET, SOCK_STREAM, getprotobyname('tcp'));

# build the address of the remote machine
$internet_addr = inet_aton($remote_host)
    or die "Couldn't convert $remote_host into an Internet address: $!\n";
$paddr = sockaddr_in($remote_port, $internet_addr);

# connect
connect(TO_SERVER, $paddr)
    or die "Couldn't connect to $remote_host:$remote_port : $!\n";

# ... do something with the socket
print TO_SERVER "Why don't you call me anymore?\n";

# and terminate the connection when we're done
close(TO_SERVER);

17.1.3 Discussion

While coding this by hand requires a lot of steps, the IO::Socket::INET class wraps them all in a convenient constructor. The important things to know are where you're going (the PeerAddr and PeerPort parameters) and how you're getting there (the Type parameter). IO::Socket::INET tries to determine these things from what you've given it. It deduces Proto from the Type and Port if possible, and assumes tcp otherwise.

PeerAddr is a string containing either a hostname ("www.oreilly.com") or an IP address ("208.201.239.36"). PeerPort is an integer, representing the port number to connect to. You can embed the port number in the address by giving an address like "www.oreilly.com:80". Type is the kind of socket to create: SOCK_DGRAM for datagrams or SOCK_STREAM for streams.

If you want a SOCK_STREAM connection to a port on a particular machine with no other options, pass a single string to IO::Socket::INET->new consisting of the hostname and port separated by a colon:

$client = IO::Socket::INET->new("www.yahoo.com:80")
    or die $@;

If an error occurs, IO::Socket::INET will return undef and $@ (not $!) will be set to the error message.

$s = IO::Socket::INET->new(PeerAddr => "Does not Exist",
                           Peerport => 80,
                           Type     => SOCK_STREAM )
    or die $@;

If your packets are disappearing into a network void, it can take a while for your inability to connect to a port to be recognized. You can decrease this time by specifying a Timeout parameter to IO::Socket::INET->new( ):

$s = IO::Socket::INET->new(PeerAddr => "bad.host.com",
                           PeerPort => 80,
                           Type     => SOCK_STREAM,
                           Timeout  => 5 )
    or die $@;

If you do this, though, there's no way to tell from $! or $@ whether you couldn't connect or whether you timed out. Sometimes it's better to set it up by hand instead of using a module.

If you have several network interfaces, the kernel decides which one to use based on your current routes. If you wish to override this default, add a Local parameter to your call to IO::Socket::INET->new. If coding by hand, do this:

$inet_addr = inet_aton("208.201.239.37");
$paddr     = sockaddr_in($port, $inet_addr);
bind(SOCKET, $paddr)         or die "bind: $!";

If you know only the name, do this:

$inet_addr = gethostbyname("www.yahoo.com")
                            or die "Can't resolve www.yahoo.com: $!";
$paddr     = sockaddr_in($port, $inet_addr);
bind(SOCKET, $paddr)        or die "bind: $!";

17.1.4 See Also

The socket, bind, connect, and gethostbyname functions in Chapter 29 of Programming Perl and in perlfunc(1); the documentation for the standard Socket, IO::Socket, and Net::hostent modules; the section on "Networking Clients" in Chapter 16 of Programming Perl and in perlipc(1); UNIX Network Programming; Recipe 17.2; Recipe 17.3