Writing a TCP Client (Perl Cookbook, 2nd Edition)

## 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

Copyright © 2003 O'Reilly & Associates. All rights reserved.