Top Banner
Chapter 5 A IO::Socket API
39

Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

Dec 20, 2015

Download

Documents

Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

Chapter 5

A IO::Socket API

Page 2: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

Socket APIs

• Chapter 4 used the built-in socket API; very C-like.• This chapter uses the IO::Socket API; easier interface.• Built-in Socket API:

• IO::Socket API

my $address = shift || DEFAULT_ADDR;my $packed_addr = inet_aton($address);my $destination = sockaddr_in(PORT,$packed_addr);socket(SOCK,PF_INET,SOCK_STREAM,IPPROTO_TCP); connect(SOCK,$destination)

my $host = shift || 'localhost';$/ = CRLF;my $socket = IO::Socket::INET->new("$host:daytime");

port numberfrom /etc/services

Page 3: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

time_of_day_tcp2.pl

#!/usr/bin/perl# file: time_of_day_tcp2.pl# Figure 5.1 Time of day client using IO::Socket

use strict;use IO::Socket qw(:DEFAULT :crlf);

my $host = shift || 'localhost';$/ = CRLF; # affects all file handles

my $socket = IO::Socket::INET->new("$host:daytime") or die "Can't connect to daytime service at $host: $!\n";

chomp(my $time = $socket->getline);print $time,"\n"

get network vrersionof \newline

page 31

Page 4: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

tcp_echo_cli2.pl

#!/usr/bin/perl# file: tcp_echo_cli2.pl# Figure 5.2: TCP echo client using IO::Socket # usage: tcp_echo_cli2.pl [host] [port]use strict;use IO::Socket;my ($bytes_out,$bytes_in) = (0,0);my $host = shift || 'localhost';my $port = shift || 'echo';my $socket = IO::Socket::INET->new("$host:$port") or die $@;while (defined(my $msg_out = STDIN->getline)) { print $socket $msg_out; my $msg_in = <$socket>; print $msg_in;

$bytes_out += length($msg_out); $bytes_in += length($msg_in);}$socket->close or warn $@;print STDERR "bytes_sent = $bytes_out, bytes_received = $bytes_in\n";

supposedly theerror message of the last eval()

/usr/lib/perl5/5.8.5/i386-linux-thread-multi/IO/Socket.pm

autoflush(true) is the defaultfor IO::Socket objects

Page 5: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

IO::Socket Hierarchy:

IO::Handle

IO::File IO::Pipe IO::Socket

IO::Socket::INET IO::Socket::UNIX

never create an IO::Socket object; always a subobject

Page 6: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

IO::Socket::INET->new():

• $socket inherits all IO::Handle funtionality but also includes accept(), connect(), bind() and sockopt().

• Returns a new connection object or undef and $!. $@ contains a more verbose error message.

• Combines socket(), connect() and sockaddr_in().

$socket = IO::Socket::INET->new(@args);

Page 7: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

Parameter passing styles (1):

• Parameters can be passed in two styles:

wuarchive.wustl.edu:echowuarchive.wustl.edu:7wuarchive.wustl.edu:echo(7)128.252.120.8:echo128.252.120.8:echo(7)128.252.120.8:7

fallback

Page 8: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

Parameter passing styles (2):

• You can specify many additional parameters

my $echo = IO::Socket::INET->new( PeerAddr => ‘wuarchive.wustl.edu’, PeerPort => ‘echo(7)’, Type => SOCK_STREAM, Proto => ‘tcp’);

Page 9: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

Parameter passing styles (3):

• Complete list of parameters for new():

PeerAddr Remote host address <hname | IPAddr>[:<port>]

PeerHost Same as PeerAddr ditto

PeerPort Remote port or service <service or number>

LocalAddr Local host bind address <hname | IPAddr>[:<port>]

LocalHost Same as LocalAddr ditto

LocalPort Local host bind port <number>

Proto Protocol name (number) <name or number>

Type Socket type SOCK_STREAM | SOCK_DGRAM

Listen Queue size for listen <number>

Reuse Set SO_REUSEAADDR

before binding

true | false

Timeout Timeout Value <number>

Multihomed Try all addresses on multihomed hosts.

true | false

Argument Description Value

client

server

requiredforservers

handy toshortenconnect()block

uses DNSand triesall IPAddrs

Page 10: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

Parameter Passing Examples:

my $sock = IO::Socket::INET->new(Proto => ‘tcp’, PeerAddr => ‘www.yahoo.com’, PeerPort => ‘http(80)’);

my $sock = IO::Socket::INET->new(Proto => ‘tcp’, LocalPort => 2007, Listen => 128);

my $udp = IO::Socket::INET->new(Proto => ‘udp’);

client example

server example

client/server example

Page 11: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

IO::Socket Methods:

• accept() works like the built-in function. The new socket inherits all the listener parameters. In the list context it also returns a packed address.

• These three functions are used if you do not supply all arguments to IO::Socket::INET->new().

$connected_socket = $listen_socket->accept();($connected_socket,$remote_addr) = $listen_socket->accept();

$rtn_val = $sock->connect($dest_addr);$rtn_val = $sock->bind($my_addr);$rtn_val = $sock->listen($ax_queue);

$sock = IO::Socket::INET->new(Proto => ‘tcp’);$dest_addr = sockaddr_in(…);$sock->connect($dest_addr);

Page 12: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

IO::Socket Methods (2):

• For convenience sake, versions of connect() and bind() exist that take unpacked values.

• Like the function-oriented call, this shuts down all copies of a socket, even in forked children.

$return_val = $sock->connect($port,$host);$return_val = $ sock- >bind($port,$host);

$rtn_val = $sock->shutdown($how);

Page 13: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

IO::Socket Methods (3):

• These are simple wrappers around the function-oriented equivalents. They return packed addresses, unpack them with sockaddr_in().

• All these functions unpack their results. However, the results of sockaddr() and peeraddr() are still binary and need to be processed by inet_ntoa().

$my_addr = $sock->sockname();$her_addr = $ sock- > peername();

$result = $sock->sockport(); $result = $sock->peerport();$result = $sock->sockaddr();$result = $sock->peerport();

Page 14: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

IO::Socket Methods (4):

• These go one step beyond sockname() and peername() and return IP addresses in dotted decimal (a.b.c.d).

• This example recovers the DNS name of the peer connection or else its IP address if it is not registered with DNS.

$my_name = $sock->sockhost();$her_name = $ sock- > peerhost();

$peer = gethostbyaddr($sock->peeraddr(), AF_INET) || $sock->peerhost();

Page 15: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

IO::Socket Methods (5):

• These three functions return integers. These are “getters” only.

• Returns true if connected to a remote host; false otherwise. It works by calling peername().

$result = $sock->connected();

$protocol = $sock->protocol();$type = $sock->socktype();$domain = $sock->sockdomain();

Page 16: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

IO::Socket Methods (6):

• Used to “get” or “set” an option. It wraps both getsockopt() and setsockopt(). It is more user friendly than getsockopt() since it assumes SOL_SOCKET level. It is also user friendly in that it unpacks binary results into integers. SO_LINGER has an 8-byte binary result and this is not unpacked for some reason.

$value = $sock->sockopt($option [,value]);

Page 17: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

sockopt() Example:

• This function, if we looked at its source code, would need to look something like

sub sockopt { my ($sock,$op,$v) = @_; my $R; . . . if ( $op == SO_KEEPALIVE) { if ( $v eq “” ) { # get $R = getsockopt($sock,SOL_SOCKET,SO_KEEPALIVE); if (defined $R ) { return unpack(“I”,$R); } else { return undef; } } else { # set } } . . .}

Page 18: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

IO::Socket Methods (7):

• Used to “get” or “set” timeout. This value is used by connect() and accept(). Called with a numeric value it sets the timeout value and returns the old value. Called with no value it returns the current value.

$value = $sock->timeout([$timeout]);

use IO::Socket; . . .$sock->timeout(5);while (1) { &housekeeping(); next unless $session = $sock->accept(); # process $session;}

if the server has noclients then it calls housekeeping() onceevery 5 seconds

accept() will timeoutafter 5 seconds

Page 19: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

IO::Socket Methods (8):

• The front-ends for send() and recv() and will be discussed when we look at UDP.

• Can’t use timeout() on these functions. Instead we can use the eval{ } trick.

$bytes = $sock->send($data [, $flags, $destination]);$address = $sock->recv($buffer, $length [, $flags]);

eval { local $SIG{ALRM} = {exit 1;}; alarm(5); $address = $sock->recv($buffer,$length); if (defined $address) { return ($address, $buffer); } else { return undef; }}alarm(0);

($Addr,$Buf) =

alarm fires in 5 secondsand exits the eval { } block.

Page 20: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

timeout() observation:

• The text says that unless timeout(n) is called then you can not interrupt connect() or accept() with a signal. I have not found this to be true.

• Even with no timeout specified by me the INT signal still interrupts accept().

Page 21: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

Echo server Revisited:

#!/usr/bin/perl# file: tcp_echo_serv2.pl# Figure 5.4: The reverse echo server, using IO::Socket# usage: tcp_echo_serv2.pl [port]

use strict;use IO::Socket qw(:DEFAULT :crlf);use constant MY_ECHO_PORT => 2007;$/ = CRLF;my ($bytes_out,$bytes_in) = (0,0);my $quit = 0;$SIG{INT} = sub { $quit++ }; my $port = shift || MY_ECHO_PORT;my $sock = IO::Socket::INET->new( Listen => 20, LocalPort => $port, Timeout => 60*60, Reuse => 1) or die "Can't create listening socket: $!\n";

1 hour timeout

Page 22: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

Echo server Revisited (2):

warn "waiting for incoming connections on port $port...\n";while (!$quit) { next unless my $session = $sock->accept();

my $peer = gethostbyaddr($session->peeraddr,AF_INET) || $session->peerhost; my $port = $session->peerport; warn "Connection from [$peer,$port]\n"; while (<$session>) { $bytes_in += length($_); chomp; my $msg_out = (scalar reverse $_) . CRLF; print $session $msg_out; $bytes_out += length($msg_out); } warn "Connection from [$peer,$port] finished\n"; close $session;}print STDERR "bytes_sent = $bytes_out, bytes_received = $bytes_in\n";close $sock;

returns undef if timeout expires

what if remote host notregistered with DNS?

what makes us quit gracefully

Page 23: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

Web Client:

• Reads web server output as raw text; prints without making it pretty.

• URL syntax:

• Our program must parse a URL to connect to the desired webserver. This is the hard part.

http://hostname[:port][/path/to/document[#fragment]]

optional

port missing, 80 is assumed path missing; look for index.html

fragment missing; entire document

Page 24: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

Web Client (2);

• After 3WHS you send the following message to a webserver.

• The reply that comes back looks like:

GET /path/to/document HTTP/1.0 CRLF CRLF

HTTP/1.1 200 OK CRLFDate: Tue, 14 Mar 2006 16:53:58 GMT CRLFServer: Apache/2.0.52 (Red Hat) CRLFLast-Modified: Tue, 07 Mar 2006 23:02:09 GMT CRLFETag: "e24123-1ab2-40e6fa2015e40“ CRLFAccept-Ranges: bytes CRLFContent-Length: 6834 CRLFConnection: close CRLFContent-Type: text/html; charset=UTF-8 CRLFCRLF<TITLE> Andrew Pletch </TITLE> …

header:consumed by browser,format fixed

desired content:displayed by browser;format varies

Page 25: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

Web Client (code):

#!/usr/bin/perl# file: web_fetch.pl# Figure 5.5: Simple web page fetcheruse strict;use IO::Socket qw(:DEFAULT :crlf);$/ = CRLF . CRLF;my $data;my $url = shift or die "Usage: web_fetch.pl <URL>\n";

my ($host,$path) = $url =~ m!^http://([^/]+)(/[^\#]*)! or die "Invalid URL.\n";

my $socket = IO::Socket::INET->new(PeerAddr => $host, PeerPort => 'http(80)') or die "Can't connect: $!";print $socket "GET $path HTTP/1.0",CRLF,CRLF; # sendmy $header = <$socket>; # read the entire header$header =~ s/$CRLF/\n/g; # replace CRLF with logical newlineprint $header;print $data while read($socket,$data,1024) > 0;

Using <>, a single read goes until it sees a pair of CRLF characters.Does not affect definition of ‘\n’

see next page

read() pays no attention to $/

Page 26: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

Search Patterns:

• What does it all mean?

my ($host,$path) = $url =~ m!^http://([^/]+)(/[^\#]*)!

patterns surrounded by ( ) arecaptured and returned. If no variableis specified then they are returned to $1, $2, …

pattern matching operator; $url is inputand it this is substitution, also output

use m if delimiter is changed (to ! since normal delimiter is /)

beginning of line anchor

([^/]+) means a pattern of one or more characters, excluding /

(/[^\#]*) means a pattern that begins with a / and is followed by one or more characters that are not # (escaped)

Page 27: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

IO::Socket performance:

• Usually adds to memory usage – 880KB to 1.5MB.• Loads more slowly but runs with same speed.• Some IO::Socket functions are just wrappers.

• Some IO::Socket functions are a big imporvement – IO::Socket::accept() returns a connected socket; accept() returns the address of socket and a file handle.

$socket->syswrite(“A man, a plan, a canal, panama!”);

syswrite($socket, “A man, a plan, a canal, panama!”);

Page 28: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

Concurrency:

• We want our application to do two things at once – read from the keyboard or network connection.

• The following example of a chat client doesn’t do this.

#!/usr/bin/perl# file: gab1.pl# Figure 5.6: An incorrect implementation of a gab client# warning: this doesn't really work

use strict;use IO::Socket qw(:DEFAULT :crlf);my $host = shift or die "Usage: gab1.pl host [port]\n";my $port = shift || 'echo';

my $socket = IO::Socket::INET->new(PeerAddr => $host, PeerPort => $port) or die "Can't connect: $!";

Page 29: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

gab1.pl (cont):

my ($from_server,$from_user);

LOOP:while (1) { { # localize change to $/ local $/ = CRLF; last LOOP unless $from_server = <$socket>; chomp $from_server; } print $from_server,"\n";

last unless $from_user = <>; chomp($from_user); print $socket $from_user,CRLF;}

here, $/ is just ‘\n’

this example normally fails since it tries to read a single line from the server before it tries to read a single line from stdin.

Page 30: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

gab1.pl works!

• However, if gab1.pl connects to an ftp server it works, for a while.

• Thus ends the single line exchange and now it won’t work since the command HELP, for example, receives multiple output lines but only if we continue to type something. We are out of synch.

./gab1.pl wyvern.cs.newpaltz.edu 21220 (vsFTPd 2.0.1)user pletcha331 Please specify the password.PASS xxxxxxx230 Login successful.

Page 31: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

gab1.pl (alternative):

my ($from_server,$from_user);

LOOP:while (1) { { # localize change to $/ local $/ = CRLF; while ( $from_server = <$socket> ) { chomp $from_server; print $from_server,"\n"; } last unless $from_user = <>; chomp($from_user); print $socket $from_user,CRLF;}

this fails; after it gets thefirst line from the serverit continues to wait for more from the server andnever gets to read what you typing at the keyboard. Thisis called deadlock.

None of the easy fixes fixesthe problem. This is because when connecting to an ftpserver, the server sends the first data.

Page 32: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

gab1.pl Solution:

• Decouple the read from the connection and the read from STDIN.

• Isolate the reading tasks in two independent and concurrent processes that won’t block each other.

• At this point we only have fork() that will allow us to do this.

• The parent is responsible for copying data from STDIN to the network connection.

• The child is responsible for the opposite direction.• Two closing scenarios:

– server closes, child reads EOF, exits and must notify parent– user calls it quits, parent reads EOF and must notify child

Page 33: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

gab2.pl:

• Child notifies parent. This is easy, when the child exits a CHLD signal is sent to the parent. The parent just needs to install a CHLD signal handler.

• Once the user closes STDIN the parent could kill() the child. This may be premature. There may be data still coming back to the server.

• A cleaner way is for the parent, once it gets an EOF from the user, closes its end of the connection.

• The server sees this and closes its end. • The child gets the message from the server.

Page 34: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

Closing a connection in a forked client:

time

parent

child

parent

child

parent

child

parent

child

parent

server

server

server

user_to_host()

host_to_user()

shutdown(1):FIN

sleep()

EOF:FIN

sleep()

CHLD

exit()

exit()

no data lost, all arrives before EOF.

notice we use shutdown(1) andnot close(). why?

Page 35: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

What happens if the server sends the first FIN?

time

parent

child

parent

child

parent

child

parent

server

server

server

user_to_host()

host_to_user()

EOF:FIN

CHLD

exit()

exit()

shutdown(1):FIN

Page 36: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

gab2.pl (code):

#!/usr/bin/perl# file: gab2.pl# Figure 5.8: A working implementation of a gab client

# usage: gab2.pl [host] [port]# Forking TCP network client

use strict;use IO::Socket qw(:DEFAULT :crlf);

my $host = shift or die "Usage: gab2.pl host [port]\n";my $port = shift || 'echo';

my $socket = IO::Socket::INET->new("$host:$port") or die $@;

my $child = fork();die "Can't fork: $!" unless defined $child;

Page 37: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

gab2.pl (code):

if ($child) { $SIG{CHLD} = sub { exit 0 }; user_to_host($socket); $socket->shutdown(1); sleep;} else { host_to_user($socket); warn "Connection closed by foreign host.\n";}

sub user_to_host { my $s = shift; while (<>) { chomp; print $s $_,CRLF; }}

sub host_to_user { my $s = shift; $/ = CRLF; while (<$s>) { chomp; print $_,"\n"; }}

Page 38: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

Homework 5: Problem 7 Diagram:

gab2.plcopy 2

child 1

child 2

gab2.plcopy 1

child 1

child 2

chat serverchild 1

child 2stdin

stdout

stdin

stdout

single tcp connection

single tcp connection

Page 39: Chapter 5 A IO::Socket API. Socket APIs Chapter 4 used the built-in socket API; very C-like. This chapter uses the IO::Socket API; easier interface. Built-in.

Homework 5: Problem 8 Diagram:

chat server

gab2.plcopy 1

child 1

child 2

stdin

stdout

gab2.plcopy 2

child 1

child 2

stdin

stdout

3WHS

listen ona.b.c.d:n

3WHS

send a.b.c.d:n

3WHS

1:

2:

3:

4:

5:

gathers a.b.c.d:n

single tcp connections