Unix では、ネットワークプログラミングには socket を使う。socket は、ファイルディスクプタである。つまり、 ユーザからは普通のファイルと同様にread/writeすることができる。 しかし、ファイルの名前等はない。
Networkは、階層構造になっていて、その様々な部分でOSが関与することに なる。
実際のUnix のネットワークプログラミングでは、ホスト内部ではファイル名を アドレスに使うUnix domainと、32bit のアドレスを使うTCP/IPが主流である。 その中で、さらに、connection less のUDPと、stream connectionのTCPとに 分かれる。
#!/usr/bin/perl -w use strict; require 5.002; use Socket; use Sys::Hostname; my ( $count, $hisiaddr, $hispaddr, $histime, $host, $iaddr, $paddr, $port, $proto, $rin, $rout, $rtime, $SECS_of_70_YEARS); $SECS_of_70_YEARS = 2208988800; $iaddr = gethostbyname(hostname()); $proto = getprotobyname('udp'); $port = getservbyname('time', 'udp'); $paddr = sockaddr_in(0, $iaddr); # 0 means let kernel pick socket(SOCKET, PF_INET, SOCK_DGRAM, $proto) || die "socket: $!"; bind(SOCKET, $paddr) || die "bind: $!"; $| = 1; printf "%-12s %8s %s\n", "localhost", 0, scalar localtime time; $count = 0; for $host (@ARGV) { $count++; $hisiaddr = inet_aton($host) || die "unknown host"; $hispaddr = sockaddr_in($port, $hisiaddr); defined(send(SOCKET, 0, 0, $hispaddr)) || die "send $host: $!"; } $rin = ''; vec($rin, fileno(SOCKET), 1) = 1; # timeout after 10.0 seconds while ($count && select($rout = $rin, undef, undef, 10.0)) { $rtime = ''; ($hispaddr = recv(SOCKET, $rtime, 4, 0)) || die "recv: $!"; ($port, $hisiaddr) = sockaddr_in($hispaddr); $host = gethostbyaddr($hisiaddr, AF_INET); $histime = unpack("N", $rtime) - $SECS_of_70_YEARS ; printf "%-12s ", $host; printf "%8d %s\n", $histime - time, scalar localtime($histime); $count--; }
TCPでは、1対1でつなげるよりも、 Unixではdaemonと呼ばれる Clinet / Server モデルを構成する ことが多い。
#!/usr/bin/perl -w require 5.002; use strict; use Socket; my ($remote,$port, $iaddr, $paddr, $proto, $line); $remote = shift || 'localhost'; $port = shift || 2345; # random port if ($port =~ /\D/) { $port = getservbyname($port, 'tcp') } die "No port" unless $port; $iaddr = inet_aton($remote) || die "no host: $remote"; $paddr = sockaddr_in($port, $iaddr); $proto = getprotobyname('tcp'); socket(SOCK, PF_INET, SOCK_STREAM, $proto) || die "socket: $!"; connect(SOCK, $paddr) || die "connect: $!"; while (defined($line =)) { print $line; } close (SOCK) || die "close: $!"; exit;
#!/usr/bin/perl -Tw require 5.002; use strict; BEGIN { $ENV{PATH} = '/usr/ucb:/bin' } use Socket; use Carp; sub logmsg { print "$0 $$: @_ at ", scalar localtime, "\n" } my $port = shift || 2345; my $proto = getprotobyname('tcp'); $port = $1 if $port =~ /(\d+)/; # untaint port number socket(Server, PF_INET, SOCK_STREAM, $proto) || die "socket: $!" ; setsockopt(Server, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)) || die "setsockopt: $!"; bind(Server, sockaddr_in($port, INADDR_ANY)) || die "bind: $!"; listen(Server,SOMAXCONN) || die "listen: $!" ; logmsg "server started on port $port"; my $paddr; $SIG{CHLD} = \&REAPER; for ( ; $paddr = accept(Client,Server); close Client) { my($port,$iaddr) = sockaddr_in($paddr); my $name = gethostbyaddr($iaddr,AF_INET); logmsg "connection from $name [", inet_ntoa($iaddr), "] at port $port"; print Client "Hello there, $name, it's now ", scalar localtime, "\n"; }