ch17_05.htm
来自「By Tom Christiansen and Nathan Torkingto」· HTM 代码 · 共 492 行
HTM
492 行
<HTML><HEAD><TITLE>Recipe 17.4. Setting Up a UDP Client (Perl Cookbook)</TITLE><METANAME="DC.title"CONTENT="Perl Cookbook"><METANAME="DC.creator"CONTENT="Tom Christiansen & Nathan Torkington"><METANAME="DC.publisher"CONTENT="O'Reilly & Associates, Inc."><METANAME="DC.date"CONTENT="1999-07-02T01:44:30Z"><METANAME="DC.type"CONTENT="Text.Monograph"><METANAME="DC.format"CONTENT="text/html"SCHEME="MIME"><METANAME="DC.source"CONTENT="1-56592-243-3"SCHEME="ISBN"><METANAME="DC.language"CONTENT="en-US"><METANAME="generator"CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"><LINKREV="made"HREF="mailto:online-books@oreilly.com"TITLE="Online Books Comments"><LINKREL="up"HREF="ch17_01.htm"TITLE="17. Sockets"><LINKREL="prev"HREF="ch17_04.htm"TITLE="17.3. Communicating over TCP"><LINKREL="next"HREF="ch17_06.htm"TITLE="17.5. Setting Up a UDP Server"></HEAD><BODYBGCOLOR="#FFFFFF"><img alt="Book Home" border="0" src="gifs/smbanner.gif" usemap="#banner-map" /><map name="banner-map"><area shape="rect" coords="1,-2,616,66" href="index.htm" alt="Perl Cookbook"><area shape="rect" coords="629,-11,726,25" href="jobjects/fsearch.htm" alt="Search this book" /></map><div class="navbar"><p><TABLEWIDTH="684"BORDER="0"CELLSPACING="0"CELLPADDING="0"><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch17_04.htm"TITLE="17.3. Communicating over TCP"><IMGSRC="../gifs/txtpreva.gif"ALT="Previous: 17.3. Communicating over TCP"BORDER="0"></A></TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="228"><B><FONTFACE="ARIEL,HELVETICA,HELV,SANSERIF"SIZE="-1"><ACLASS="chapter"REL="up"HREF="ch17_01.htm"TITLE="17. Sockets"></A></FONT></B></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch17_06.htm"TITLE="17.5. Setting Up a UDP Server"><IMGSRC="../gifs/txtnexta.gif"ALT="Next: 17.5. Setting Up a UDP Server"BORDER="0"></A></TD></TR></TABLE></DIV><DIVCLASS="sect1"><H2CLASS="sect1"><ACLASS="title"NAME="ch17-37500">17.4. Setting Up a UDP Client</A></H2><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch17-pgfId-562">Problem<ACLASS="indexterm"NAME="ch17-idx-1000004718-0"></A><ACLASS="indexterm"NAME="ch17-idx-1000004718-1"></A><ACLASS="indexterm"NAME="ch17-idx-1000004718-2"></A><ACLASS="indexterm"NAME="ch17-idx-1000004718-3"></A></A></H3><PCLASS="para">You want to exchange messages with another process using UDP (datagrams).</P></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch17-pgfId-568">Solution</A></H3><PCLASS="para">To set up a UDP socket handle, use either the low-level Socket module on your own filehandle:</P><PRECLASS="programlisting">use Socket;socket(SOCKET, PF_INET, SOCK_DGRAM, getprotobyname("udp")) or die "socket: $!";</PRE><PCLASS="para">or else IO::Socket, which returns an anonymous one:</P><PRECLASS="programlisting">use IO::Socket;$handle = IO::Socket::INET->new(Proto => 'udp') or die "socket: $@"; # yes, it uses $@ here</PRE><PCLASS="para">Then to send a message to a machine named <CODECLASS="literal">$HOSTNAME</CODE> on port number <CODECLASS="literal">$PORTNO</CODE>, use:</P><PRECLASS="programlisting">$ipaddr = inet_aton($HOSTNAME);$portaddr = sockaddr_in($PORTNO, $ipaddr);send(SOCKET, $MSG, 0, $portaddr) == length($MSG) or die "cannot send to $HOSTNAME($PORTNO): $!";</PRE><PCLASS="para">To receive a message of length no greater than $<CODECLASS="literal">MAXLEN</CODE>, use:</P><PRECLASS="programlisting">$portaddr = recv(SOCKET, $MSG, $MAXLEN, 0) or die "recv: $!";($portno, $ipaddr) = sockaddr_in($portaddr);$host = gethostbyaddr($ipaddr, AF_INET);print "$host($portno) said $MSG\n";</PRE></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch17-pgfId-608">Discussion</A></H3><PCLASS="para"><ACLASS="indexterm"NAME="ch17-idx-1000004726-0"></A>Datagram sockets are unlike stream sockets. Streams provide sessions, giving the illusion of a stable connection. You might think of them as working like a telephone call - expensive to set up, but once established, reliable and easy to use. Datagrams, though, are more like the postal system - it's cheaper and easier to send a letter to your friend on the other side of the world than to call them on the phone. Datagrams are easier on the system than streams. You send a small amount of information one message at a time. But your messages' delivery isn't guaranteed, and they might arrive in the wrong order. Like a small post box, the receiver's queue might fill up and cause further messages to be dropped.</P><PCLASS="para">Why then, if datagrams are unreliable, do we have them? Because some applications are most sensibly implemented in terms of datagrams. For instance, in streaming audio, it's more important that the stream as a whole be preserved than that every packet get through, especially if packets are being dropped because there's not enough bandwidth for them all. Another use for datagrams is broadcasting, which corresponds to mass mailing of advertisements in the postal model, and is equally popular in most circles. One use for broadcast packets is to send out a message to your local subnet saying "Hey, is there anybody around here who wants to be my server?"</P><PCLASS="para">Because datagrams don't provide the illusion of a lasting connection, you get a little more freedom in how you use them. You don't have to <CODECLASS="literal">connect</CODE> your socket to the remote end that you're sending data. Instead, address each datagram individually when you <CODECLASS="literal">send</CODE>. Assuming <CODECLASS="literal">$remote_addr</CODE> is the result of a call to <CODECLASS="literal">sockaddr_in</CODE>, do this:</P><PRECLASS="programlisting">send(MYSOCKET, $msg_buffer, $flags, $remote_addr) or die "Can't send: $!\n";</PRE><PCLASS="para">The only flag argument used much is MSG_OOB, which lets you send and receive out-of-band data in advanced applications.</P><PCLASS="para">The remote address should be a port and internet address combination returned by the Socket module's <CODECLASS="literal">sockaddr_in</CODE><ACLASS="indexterm"NAME="ch17-idx-1000004732-0"></A> function. If you want, call <CODECLASS="literal">connect</CODE> on that address instead. Then you can omit the last argument to your <CODECLASS="literal">send</CODE>s, after which they'll all go to that recipient. Unlike streams, you are free to reconnect to another machine with the same datagram socket.</P><PCLASS="para"><ACLASS="xref"HREF="ch17_05.htm#ch17-37821"TITLE="clockdrift">Example 17.1</A> is a small example of a UDP program. It contacts the UDP time port of the machine whose name is given on the command line, or of the local machine by default. This doesn't work on all machines, but those with a server will send you back a 4-byte integer packed in network byte order that represents the time that machine thinks it is. The time returned, however, is in the number of seconds since 1900. You have to subtract the number of seconds between 1900 and 1970 to feed that time to the <CODECLASS="literal">localtime</CODE> or <CODECLASS="literal">gmtime</CODE> conversion functions.</P><DIVCLASS="example"><H4CLASS="example"><ACLASS="title"NAME="ch17-37821">Example 17.1: clockdrift</A></H4><PRECLASS="programlisting">#!/usr/bin/perl# <ACLASS="indexterm"NAME="ch17-idx-1000004736-0"></A>clockdrift - compare another system's clock with this oneuse strict;use Socket;my ($host, $him, $src, $port, $ipaddr, $ptime, $delta);my $SECS_of_70_YEARS = 2_208_988_800;socket(MsgBox, PF_INET, SOCK_DGRAM, getprotobyname("udp")) or die "socket: $!";$him = sockaddr_in(scalar(getservbyname("time", "udp")), inet_aton(shift || '127.1'));defined(send(MsgBox, 0, 0, $him)) or die "send: $!";defined($src = recv(MsgBox, $ptime, 4, 0)) or die "recv: $!";($port, $ipaddr) = sockaddr_in($src);$host = gethostbyaddr($ipaddr, AF_INET);my $delta = (unpack("N", $ptime) - $SECS_of_70_YEARS) - time();print "Clock on $host is $delta seconds ahead of this one.\n";</PRE></DIV><PCLASS="para">If the machine you're trying to contact isn't alive or if its response is lost, you'll only know because your program will get stuck in the <CODECLASS="literal">recv</CODE> waiting for an answer that will never come.<ACLASS="indexterm"NAME="ch17-idx-1000004728-0"></A><ACLASS="indexterm"NAME="ch17-idx-1000004728-1"></A><ACLASS="indexterm"NAME="ch17-idx-1000004728-2"></A></P></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch17-pgfId-668">See Also</A></H3><PCLASS="para">The <ACLASS="olink"HREF="../prog/ch03_139.htm"> <CODECLASS="literal">send</CODE></A>, <ACLASS="olink"HREF="../prog/ch03_119.htm"> <CODECLASS="literal">recv</CODE></A>, <ACLASS="olink"HREF="../prog/ch03_047.htm"> <CODECLASS="literal">gethostbyaddr</CODE></A>, and <ACLASS="olink"HREF="../prog/ch03_182.htm"> <CODECLASS="literal">unpack</CODE> </A>functions in <ACLASS="olink"HREF="../prog/ch03_01.htm">Chapter 3</A> of <ACLASS="citetitle"HREF="../prog/index.htm"TITLE="Programming Perl"><CITECLASS="citetitle">Programming Perl</CITE></A> and in <ICLASS="filename">perlfunc </I>(1); the documentation for the standard Socket and IO::Socket modules; the section on <ACLASS="olink"HREF="../prog/ch06_02.htm#PERL2-CH-6-SECT-2.4.3"> "UDP: message passing"</A> in <ACLASS="olink"HREF="../prog/ch06_01.htm">Chapter 6</A> of <ACLASS="citetitle"HREF="../prog/index.htm"TITLE="Programming Perl"><CITECLASS="citetitle">Programming Perl</CITE></A> and in <ICLASS="filename">perlipc </I>(1); <CITECLASS="citetitle">Unix Network Programming</CITE>; <ACLASS="xref"HREF="ch17_06.htm"TITLE="Setting Up a UDP Server">Recipe 17.5</A></P></DIV></DIV><DIVCLASS="htmlnav"><P></P><HRALIGN="LEFT"WIDTH="684"TITLE="footer"><TABLEWIDTH="684"BORDER="0"CELLSPACING="0"CELLPADDING="0"><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch17_04.htm"TITLE="17.3. Communicating over TCP"><IMGSRC="../gifs/txtpreva.gif"ALT="Previous: 17.3. Communicating over TCP"BORDER="0"></A></TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="228"><ACLASS="book"HREF="index.htm"TITLE="Perl Cookbook"><IMGSRC="../gifs/txthome.gif"ALT="Perl Cookbook"BORDER="0"></A></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch17_06.htm"TITLE="17.5. Setting Up a UDP Server"><IMGSRC="../gifs/txtnexta.gif"ALT="Next: 17.5. Setting Up a UDP Server"BORDER="0"></A></TD></TR><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228">17.3. Communicating over TCP</TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="228"><ACLASS="index"HREF="index/index.htm"TITLE="Book Index"><IMGSRC="../gifs/index.gif"ALT="Book Index"BORDER="0"></A></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="228">17.5. Setting Up a UDP Server</TD></TR></TABLE><HRALIGN="LEFT"WIDTH="684"TITLE="footer"><FONTSIZE="-1"></DIV<!-- LIBRARY NAV BAR --> <img src="../gifs/smnavbar.gif" usemap="#library-map" border="0" alt="Library Navigation Links"><p> <a href="copyrght.htm">Copyright © 2002</a> O'Reilly & Associates. All rights reserved.</font> </p> <map name="library-map"> <area shape="rect" coords="1,0,85,94" href="../index.htm"><area shape="rect" coords="86,1,178,103" href="../lwp/index.htm"><area shape="rect" coords="180,0,265,103" href="../lperl/index.htm"><area shape="rect" coords="267,0,353,105" href="../perlnut/index.htm"><area shape="rect" coords="354,1,446,115" href="../prog/index.htm"><area shape="rect" coords="448,0,526,132" href="../tk/index.htm"><area shape="rect" coords="528,1,615,119" href="../cookbook/index.htm"><area shape="rect" coords="617,0,690,135" href="../pxml/index.htm"></map> </BODY></HTML>
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?