📄 ch16_05.htm
字号:
<html><head><title>Sockets (Programming Perl)</title><!-- STYLESHEET --><link rel="stylesheet" type="text/css" href="../style/style1.css"><!-- METADATA --><!--Dublin Core Metadata--><meta name="DC.Creator" content=""><meta name="DC.Date" content=""><meta name="DC.Format" content="text/xml" scheme="MIME"><meta name="DC.Generator" content="XSLT stylesheet, xt by James Clark"><meta name="DC.Identifier" content=""><meta name="DC.Language" content="en-US"><meta name="DC.Publisher" content="O'Reilly & Associates, Inc."><meta name="DC.Source" content="" scheme="ISBN"><meta name="DC.Subject.Keyword" content=""><meta name="DC.Title" content="Sockets"><meta name="DC.Type" content="Text.Monograph"></head><body><!-- START OF BODY --><!-- TOP BANNER --><img src="gifs/smbanner.gif" usemap="#banner-map" border="0" alt="Book Home"><map name="banner-map"><AREA SHAPE="RECT" COORDS="0,0,466,71" HREF="index.htm" ALT="Programming Perl"><AREA SHAPE="RECT" COORDS="467,0,514,18" HREF="jobjects/fsearch.htm" ALT="Search this book"></map><!-- TOP NAV BAR --><div class="navbar"><table width="515" border="0"><tr><td align="left" valign="top" width="172"><a href="ch16_04.htm"><img src="../gifs/txtpreva.gif" alt="Previous" border="0"></a></td><td align="center" valign="top" width="171"><a href="ch16_01.htm">Chapter 16: Interprocess Communication</a></td><td align="right" valign="top" width="172"><a href="ch17_01.htm"><img src="../gifs/txtnexta.gif" alt="Next" border="0"></a></td></tr></table></div><hr width="515" align="left"><!-- SECTION BODY --><h2 class="sect1">16.5. Sockets</h2><p><a name="INDEX-3063"></a><a name="INDEX-3064"></a><a name="INDEX-3065"></a>The IPC mechanisms discussed earlier all have one severe restriction:they're designed for communication between processes runningon the same computer. (Even though files can sometimes be sharedacross machines through mechanisms like NFS, locking fails miserably onmany NFS implementations, which takes away most of the fun ofconcurrent access.) For general-purpose networking, sockets arethe way to go. Although sockets were invented under BSD, theyquickly spread to other forms of Unix, and nowadays you can find asocket interface on nearly every viable operating system out there.If you don't have sockets on your machine, you're going to havetremendous difficulty using the Internet.</p><p><a name="INDEX-3066"></a><a name="INDEX-3067"></a><a name="INDEX-3068"></a><a name="INDEX-3069"></a><a name="INDEX-3070"></a>With sockets, you can do both virtual circuits (as TCP streams) anddatagrams (as UDP packets). You may be able to do even more, dependingon your system. But the most common sort of socket programming usesTCP over Internet-domain sockets, so that's the kind we cover here.Such sockets provide reliable connections that work a little bit likebidirectional pipes that aren't restricted to the local machine. Thetwo killer apps of the Internet, email and web browsing, both rely almostexclusively on TCP sockets.</p><p><a name="INDEX-3071"></a><a name="INDEX-3072"></a>You also use UDP heavily without knowing it. Every time your machinetries to find a site on the Internet, it sends UDP packets to your DNSserver asking it for the actual IP address. You might use UDP yourselfwhen you want to send and receive datagrams. Datagrams are cheaper thanTCP connections precisely because they aren't connection oriented;that is, they're less like making a telephone call and more like dropping aletter in the mailbox. But UDP also lacks the reliabilitythat TCP provides, making it more suitable for situations where youdon't care whether a packet or two gets folded, spindled, ormutilated. Or for when you know that a higher-level protocol will enforcesome degree of redundancy or fail-softness (which is what DNS does.)</p><p><a name="INDEX-3073"></a>Other choices are available but far less common. You can useUnix-domain sockets, but they only work for local communication.Various systems support various other non-IP-based protocols. Doubtlessthese are somewhat interesting to someone somewhere, but we'llrestrain ourselves from talking about them somehow.</p><p><a name="INDEX-3074"></a><a name="INDEX-3075"></a>The Perl functions that deal with sockets have the same namesas the corresponding syscalls in C, but their arguments tend todiffer for two reasons: first, Perl filehandles work differentlyfrom C file descriptors; and second, Perl already knows the lengthof its strings, so you don't need to pass that information. See<a href="ch29_01.htm">Chapter 29, "Functions"</a> for details on each socket-relatedsyscall.</p><p><a name="INDEX-3076"></a><a name="INDEX-3077"></a><a name="INDEX-3078"></a>One problem with ancient socket code in Perl was that people would usehard-coded values for constants passed into socket functions, whichdestroys portability. Like most syscalls, the socket-related onesquietly but politely return <tt class="literal">undef</tt> when they fail,instead of raising an exception. It is therefore essential to checkthese functions' return values, since if you pass them garbage, theyaren't going to be very noisy about it. If you ever see code thatdoes anything like explicitly setting <tt class="literal">$AF_INET = 2</tt>,you know you're in for big trouble. An immeasurably superior approachis to use the <tt class="literal">Socket</tt> module or the even friendlier<tt class="literal">IO::Socket</tt> module, both of which arestandard. These modules provide various constants and helperfunctions you'll need for setting up clients and servers. For optimalsuccess, your socket programs should always start out like this (anddon't forget to add the <tt class="userinput"><b>-T</b></tt> taint-checkingswitch to the shebang line for servers):<blockquote><pre class="programlisting">#!/usr/bin/perl -wuse strict;use sigtrap;use Socket; # or IO::Socket</pre></blockquote><a name="INDEX-3079"></a>As noted elsewhere, Perl is at the mercy of your C libraries for muchof its system behavior, and not all systems support all sorts ofsockets. It's probably safest to stick with normal TCP and UDP socketoperations. For example, if you want your code to stand a chance ofbeing portable to systems you haven't thought of, don't expect thereto be support for a reliable sequenced-packet protocol. Nor shouldyou expect to pass open file descriptors between unrelated processesover a local Unix-domain socket. (Yes, you can really do that on manyUnix machines--see your local <em class="emphasis">recvmsg</em>(2)manpage.)</p><p><a name="INDEX-3080"></a><a name="INDEX-3081"></a>If you just want to use a standard Internet service like mail, news,domain name service, FTP, Telnet, the Web, and so on, then insteadof starting from scratch, try using existing CPAN modules for these.Prepackaged modules designed for these include <tt class="literal">Net::SMTP</tt> (or<tt class="literal">Mail::Mailer</tt>), <tt class="literal">Net::NNTP</tt>, <tt class="literal">Net::DNS</tt>, <tt class="literal">Net::FTP</tt>, <tt class="literal">Net::Telnet</tt>,and the various HTTP-related modules. The <tt class="literal">libnet</tt> and <tt class="literal">libwww</tt>module suites both comprise many individual networking modules.Module areas on CPAN you'll want to look at are section 5 onNetworking and IPC, section 15 on WWW-related modules, and section16 on Server and Daemon Utilities.</p><p>In the sections that follow, we present several sample clients and servers without a greatdeal of explanation of each function used, as that would mostlyduplicate the descriptions we've already provided in <a href="ch29_01.htm">Chapter 29, "Functions"</a>.</p><h3 class="sect2">16.5.1. Networking Clients </h3><a name="INDEX-3082"></a><a name="INDEX-3083"></a><a name="INDEX-3084"></a><a name="INDEX-3085"></a><a name="INDEX-3086"></a><a name="INDEX-3087"></a><p>Use Internet-domain sockets when you want reliable client-servercommunication between potentially different machines.</p><p><a name="INDEX-3088"></a>To create a TCP client that connects to a server somewhere, it'susually easiest to use the standard <tt class="literal">IO::Socket::INET</tt> module:<blockquote><pre class="programlisting">use IO::Socket::INET;$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";# send something over the socket,print $socket "Why don't you call me anymore?\n";# read the remote answer,$answer = <$socket>;# and terminate the connection when we're done.close($socket);</pre></blockquote>A shorthand form of the call is good enough when you just have ahost and port combination to connect to, and are willing to usedefaults for all other fields:<blockquote><pre class="programlisting">$socket = IO::Socket::INET->new("www.yahoo.com:80") or die "Couldn't connect to port 80 of yahoo: $!";</pre></blockquote><a name="INDEX-3089"></a>To connect using the basic <tt class="literal">Socket</tt> module:<blockquote><pre class="programlisting">use Socket;# create a socketsocket(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);# connectconnect(Server, $paddr) or die "Couldn't connect to $remote_host:$remote_port: $!\n";select((select(Server), $| = 1)[0]); # enable command buffering# send something over the socketprint Server "Why don't you call me anymore?\n";# read the remote answer$answer = <Server>;# terminate the connection when doneclose(Server);</pre></blockquote><a name="INDEX-3090"></a><a name="INDEX-3091"></a>If you want to close only your side of the connection, so that theremote end gets an end-of-file, but you can still read data comingfrom the server, use the <tt class="literal">shutdown</tt> syscall for a half-close:<blockquote><pre class="programlisting"># no more writing to servershutdown(Server, 1); # Socket::SHUT_WR constant in v5.6</pre></blockquote></p><h3 class="sect2">16.5.2. Networking Servers</h3><p><a name="INDEX-3092"></a><a name="INDEX-3093"></a><a name="INDEX-3094"></a>Here's a corresponding server to go along with it. It's prettyeasy with the standard <tt class="literal">IO::Socket::INET</tt> class:<blockquote><pre class="programlisting">use IO::Socket::INET;$server = IO::Socket::INET->new(LocalPort => $server_port, Type => SOCK_STREAM, Reuse => 1, Listen => 10 ) # or SOMAXCONN or die "Couldn't be a tcp server on port $server_port: $!\n";while ($client = $server->accept()) { # $client is the new connection}close($server);</pre></blockquote>You can also write that using the lower-level <tt class="literal">Socket</tt> module:<blockquote><pre class="programlisting">use Socket;# make the socket
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -