Article 7987 of comp.lang.perl:
Xref: feenix.metronet.com comp.lang.perl:7987
Newsgroups: comp.lang.perl
Path: feenix.metronet.com!news.ecn.bgu.edu!usenet.ins.cwru.edu!howland.reston.ans.net!europa.eng.gtefsd.com!uunet!munnari.oz.au!metro!usage!news
From:
[email protected] (Cameron Simpson)
Subject: Re: Sockets and stuff question...
Message-ID: <cameron-931116200252-1-17925@crwth>
To:
[email protected] (Jim Hamilton)
Followup-To: comp.lang.perl
Sender:
[email protected]
Nntp-Posting-Host: 149.171.200.12
Reply-To:
[email protected]
Organization: CS&E Computing Facility, Uni Of NSW, Oz
References: <
[email protected]>
Errors-To:
[email protected]
Date: Tue, 16 Nov 1993 09:03:05 GMT
Return-Receipt-To:
[email protected]
Lines: 271
[email protected] (Jim Hamilton) writes:
| 1) In my reading of "the book", I am left with the impression that a socket
| should be bi-directional, is this true and how do you use the other
| direction?
Yes. Well, you could just try reading from it (or writing if you were
reading); you can use the one stream. You may need to flush the stream
in between. To save that hassle I tend to dup the stream:
# assume TO has been bound, connected, etc
open(FROM,"<&TO") || die "blah blah blah: $!";
This makes two stdio streams.
| 2) Is there a cool way of catching the output of a command executed by
| system() other than the very crude way I did it. I appended to the command
| a redirection into a temp file which I later reopen to read and send
| back across the socket so the client can print out the results.
`command` ?
Or, if you want pure command output fed back to the client:
if (fork == 0)
# child
{ open(STDOUT,">&SOCKET") || die ...
close(SOCKET); # handle now on STDOUT
open(STDERR,">&SOCKET") # you may not want this
exec(command args)
die "exec fails: $!\n";
}
| 3) In order to allow multiple clients to call the server I implemented
| a crude protocol, which is the client sends his hostname across the
| socket before the command, so the server knows who to later connect to.
But if you use the connection both ways the server doesn't need to make
another connection, nor to trust the hostname/port coming from the client...
| The funky thing is the name appears to be interpreted as a character
| not a string. Assuming the hostname is "poobah" saved into $them, and
| is read in on the server side from the socket, if I print($them) I get
| "poobah", if I chop($them) it I get "", if I just us it in gethostbyname($them)
| (as in the client pg. 343) I don't get the correct results. BUT if I assign
| $bogus = chop($them);, then use $them in the gethostbyname$them(), it works,
| What is going on here?
Not sure, really; in case you're curious I append the TCP wrappers I use.
They're a combination of the Book and some C wrappers I have I adapted
(i.e. the book's calls, my subroutine interface).
- Cameron Simpson
[email protected], DoD#743
--
Automobile: device used to drive slower than motorcycles.
#!/bin/sh
#
sed 's/^X//' > tcp.pl <<'EOF-/home/cs/orchestra/crwth/1/cameron/etc/pl/cs/tcp.pl'
X#!/usr/local/bin/perl
X
Xrequire 'sys/socket.ph';
Xrequire 'cs/net.pl';
X
Xpackage tcp;
X
X{ local($name,$aliases);
X
X ($name,$aliases,$proto)=getprotobyname('tcp');
X die "$0: can't look up tcp protocol" unless defined($proto);
X}
X
X$SOCK='TCPSOCK0000';
Xsub tcp'rwopen # (host,port) -> (FILE)
X { local($rhost,$port)=@_;
X local($name,$aliases,$type,$len,$raddr);
X local($dummy);
X
X ($port,$dummy)=&net'service($port,'tcp')
X unless $port =~ /^\d+$/;
X ($name,$aliases,$type,$len,$raddr)=gethostbyname($rhost);
X
X local($local,$remote);
X $local =&net'mkaddr_in(0,$net'hostaddr);
X $remote=&net'mkaddr_in($port,$raddr);
X
X local($sockf)=$SOCK++;
X
X ((warn "socket: $!"), return undef)
X unless socket($sockf,&main'AF_INET,&main'SOCK_STREAM,$tcp'proto);
X
X ((warn "$!"), close($sockf), return undef)
X unless bind($sockf,$local) && connect($sockf,$remote);
X
X local($s)=select($sockf); $|=1; select($s);
X
X "tcp'".$sockf;
X }
X
Xsub tcp'rwopen2 # (host,port) -> (FROM,TO)
X { local($TO)=&rwopen;
X
X return undef unless defined($TO);
X
X local($FROM);
X $FROM="tcp'".$tcp'SOCK++;
X (close($TO), return undef) unless open($FROM,'<&'.fileno($TO));
X
X ($FROM,$TO);
X }
X
Xsub tcp'bind # (port) -> FILE
X { local($port)=@_;
X local($name,$aliases);
X local($FILE,$dummy);
X
X ($port,$dummy)=&net'service($port,'tcp')
X unless $port =~ /^\d+$/;
X
X $FILE=$SOCK++;
X ((warn "socket: $!"), return undef)
X unless socket($FILE, &main'PF_INET, &main'SOCK_STREAM, $tcp'proto);
X
X $name=&net'mkaddr_in($port, "\0\0\0\0");
X ((warn "bind: $!"), return undef)
X unless bind($FILE, $name);
X
X listen($FILE,10) || warn("listen($FILE,10): $!");
X
X "tcp'".$FILE;
X }
X
X1;
EOF-/home/cs/orchestra/crwth/1/cameron/etc/pl/cs/tcp.pl
sed 's/^X//' > udp.pl <<'EOF-/home/cs/orchestra/crwth/1/cameron/etc/pl/cs/udp.pl'
X#!/usr/local/bin/perl
X#
X# Package for UDP connections:
X#
X# $udp'proto Protocol number for UDP.
X# &udp'bind(port) -> FILE Make a UDP socket at port (0 for any)
X#
X
Xrequire 'sys/socket.ph';
Xrequire 'cs/net.pl';
X
Xpackage udp;
X
X{ local($name,$aliases);
X
X ($name,$aliases,$proto)=getprotobyname('udp');
X die "$0: can't look up udp protocol" unless defined($proto);
X}
X
X$SOCK='UDPSOCK0000';
Xsub udp'bind # (port) -> FILE
X { local($port)=@_;
X local($name,$aliases);
X local($FILE,$dummy);
X
X
X ($port,$dummy)=&net'service($port,'udp')
X unless $port =~ /^\d+$/;
X $FILE=$SOCK++;
X ((warn "socket: $!"), return undef)
X unless socket($FILE, &main'PF_INET, &main'SOCK_DGRAM, $udp'proto);
X
X $name=&net'mkaddr_in($port, "\0\0\0\0");
X ((warn "bind: $!"), return undef)
X unless bind($FILE, $name);
X
X "udp'".$FILE;
X }
X
Xsub udp'send # (sock,data,port,addr) -> chars sent or undef
X { local($SOCK,$_,$port,$addr)=@_;
X
X $_=send($SOCK,$_,0,&net'mkaddr_in($port,$addr));
X
X defined($_) ? $_ : undef;
X }
X
Xsub udp'recv # ($SOCK) -> ($data,$port,$addr) or undef
X { local($_,$from);
X
X $from=recv(shift,$_,65536,0);
X
X return undef if !defined($from);
X
X local($family,$port,$addr)=unpack($net'sockaddr,$from);
X
X ($_,$port,$addr);
X }
X
X1; # for require
EOF-/home/cs/orchestra/crwth/1/cameron/etc/pl/cs/udp.pl
sed 's/^X//' > net.pl <<'EOF-/home/cs/orchestra/crwth/1/cameron/etc/pl/cs/net.pl'
X#!/usr/local/bin/perl
X#
X# Package for network stuff.
X#
X# $net'sockaddr Pack/Unpack format for a sockaddr.
X# $net'hostname Local host name.
X# $net'hostaddr Local host address.
X# &net'getaddr(SOCK) -> (family,port,addr)
X# Return address of socket.
X# &net'mkaddr(family,port,addr) -> sockaddr
X# Produce machine socket address.
X# &net'mkaddr(port,addr) -> sockaddr_in
X# Produce machine socket internet address.
X# &net'addr2a(addr) -> "x.x.x.x" Produce decimal rep of address.
X#
X
Xrequire 'sys/socket.ph';
X
Xpackage net;
X
X{ local($name,$aliases,$type,$len);
X
X $sockaddr='S n a4 x8';
X chop($hostname=`hostname`);
X die "$0: can't look up hostname" unless length($hostname);
X ($name,$aliases,$type,$len,$hostaddr)=gethostbyname($hostname);
X die "$0: can't look up hostaddr($hostname)" unless defined($name);
X}
X
Xpackage main;
X
Xsub net'service # (servname,protocolname) -> (port-number,proto-number)
X { local($serv,$proto)=@_;
X local($protoname,$etc1,$etc2);
X
X if ($proto !~ /^\d+$/)
X { ($protoname,$etc2,$proto)=getprotobyname($proto);
X # print STDERR "byname: name=$protoname, num=$proto\n";
X }
X else
X { ($protoname,$etc2,$proto)=getprotobynumber($proto);
X # print STDERR "bynumber: name=$protoname, num=$proto\n";
X }
X
X ($etc1,$etc2,$serv)=getservbyname($serv,$protoname)
X unless $serv =~ /^\d+$/;
X
X # print STDERR "net'service(@_) -> ($serv $proto)\n";
X ($serv,$proto);
X }
X
Xsub net'getaddr # (SOCK) -> (family,port,myaddr)
X { unpack($net'sockaddr,getsockname($_[$[]));
X }
X
Xsub net'mkaddr_in # (port,address) -> sockaddr_in
X { &net'mkaddr(&main'AF_INET,@_);
X }
X
Xsub net'mkaddr # (family,port,address) -> sockaddr
X { pack($net'sockaddr,@_);
X }
X
Xsub net'addr2a # address -> "x.x.x.x"
X { sprintf("%d.%d.%d.%d",unpack("CCCC",shift));
X }
X
X1;
EOF-/home/cs/orchestra/crwth/1/cameron/etc/pl/cs/net.pl
exit 0