📄 ch17_06.htm
字号:
<HTML><HEAD><TITLE>Recipe 17.5. Setting Up a UDP Server (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:31Z"><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_05.htm"TITLE="17.4. Setting Up a UDP Client"><LINKREL="next"HREF="ch17_07.htm"TITLE="17.6. Using UNIX Domain Sockets"></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_05.htm"TITLE="17.4. Setting Up a UDP Client"><IMGSRC="../gifs/txtpreva.gif"ALT="Previous: 17.4. Setting Up a UDP Client"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_07.htm"TITLE="17.6. Using UNIX Domain Sockets"><IMGSRC="../gifs/txtnexta.gif"ALT="Next: 17.6. Using UNIX Domain Sockets"BORDER="0"></A></TD></TR></TABLE></DIV><DIVCLASS="sect1"><H2CLASS="sect1"><ACLASS="title"NAME="ch17-26647">17.5. Setting Up a UDP Server</A></H2><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch17-pgfId-678">Problem<ACLASS="indexterm"NAME="ch17-idx-1000004738-0"></A><ACLASS="indexterm"NAME="ch17-idx-1000004738-1"></A><ACLASS="indexterm"NAME="ch17-idx-1000004738-2"></A></A></H3><PCLASS="para">You want to write a UDP server.</P></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch17-pgfId-684">Solution</A></H3><PCLASS="para">First <CODECLASS="literal">bind</CODE> to the port the server is to be contacted on. With IO::Socket, this is easily accomplished:</P><PRECLASS="programlisting">use IO::Socket;$server = IO::Socket::INET->new(LocalPort => $server_port, Proto => "udp") or die "Couldn't be a udp server on port $server_port : $@\n";</PRE><PCLASS="para">Then, go into a loop receiving messages:</P><PRECLASS="programlisting">while ($him = $server->recv($datagram, $MAX_TO_READ, $flags)) { # do something} </PRE></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch17-pgfId-706">Discussion</A></H3><PCLASS="para">Life with UDP is much simpler than life with TCP. Instead of accepting client connections one at a time and committing yourself to a long-term relationship, take messages from clients as they come in. The <CODECLASS="literal">recv</CODE> function returns the address of the sender, which you must then decode.</P><PCLASS="para"><ACLASS="xref"HREF="ch17_06.htm#ch17-37044"TITLE="udpqotd">Example 17.2</A> is a small UDP-based server that just sits around waiting for messages. Every time a message comes in, we find out who sent it and send them a message based on the previous message, and then save the new message.</P><DIVCLASS="example"><H4CLASS="example"><ACLASS="title"NAME="ch17-37044">Example 17.2: udpqotd</A></H4><PRECLASS="programlisting">#!/usr/bin/perl -w# <ACLASS="indexterm"NAME="ch17-idx-1000004742-0"></A>udpqotd - UDP message serveruse strict;use IO::Socket;my($sock, $oldmsg, $newmsg, $hisaddr, $hishost, $MAXLEN, $PORTNO);$MAXLEN = 1024;$PORTNO = 5151;$sock = IO::Socket::INET->new(LocalPort => $PORTNO, Proto => 'udp') or die "socket: $@";print "Awaiting UDP messages on port $PORTNO\n";$oldmsg = "This is the starting message.";while ($sock->recv($newmsg, $MAXLEN)) { my($port, $ipaddr) = sockaddr_in($sock->peername); $hishost = gethostbyaddr($ipaddr, AF_INET); print "Client $hishost said ``$newmsg''\n"; $sock->send($oldmsg); $oldmsg = "[$hishost] $newmsg";} die "recv: $!";</PRE></DIV><PCLASS="para">This program is easier using IO::Socket than the raw Socket module. We don't have to say where to send the message because the library keeps track of who sent the last message and stores that information away on the <CODECLASS="literal">$sock</CODE> object. The <CODECLASS="literal">peername</CODE> method retrieves it for decoding.</P><PCLASS="para">You can't use the <EMCLASS="emphasis">telnet</EM> program to talk to this server. You have to use a dedicated client. One is shown in <ACLASS="xref"HREF="ch17_06.htm#ch17-13236"TITLE="udpmsg">Example 17.3</A>.</P><DIVCLASS="example"><H4CLASS="example"><ACLASS="title"NAME="ch17-13236">Example 17.3: udpmsg</A></H4><PRECLASS="programlisting">#!/usr/bin/perl -w# <ACLASS="indexterm"NAME="ch17-idx-1000004743-0"></A>udpmsg - send a message to the udpquotd serveruse IO::Socket;use strict;my($sock, $server_host, $msg, $port, $ipaddr, $hishost, $MAXLEN, $PORTNO, $TIMEOUT);$MAXLEN = 1024;$PORTNO = 5151;$TIMEOUT = 5;$server_host = shift;$msg = "@ARGV";$sock = IO::Socket::INET->new(Proto => 'udp', PeerPort => $PORTNO, PeerAddr => $server_host) or die "Creating socket: $!\n";$sock->send($msg) or die "send: $!";eval { local $SIG{ALRM} = sub { die "alarm time out" }; alarm $TIMEOUT; $sock->recv($msg, $MAXLEN) or die "recv: $!"; alarm 0; 1; # return value from eval on normalcy} or die "recv from $server_host timed out after $TIMEOUT seconds.\n";($port, $ipaddr) = sockaddr_in($sock->peername);$hishost = gethostbyaddr($ipaddr, AF_INET);print "Server $hishost responded ``$msg''\n";</PRE></DIV><PCLASS="para">This time when we create the socket, we supply a peer host and port at the start, allowing us to omit that information in the <CODECLASS="literal">send</CODE>.</P><PCLASS="para">We've added an <CODECLASS="literal">alarm</CODE> timeout in case the server isn't responsive, or maybe not even alive. Because <CODECLASS="literal">recv</CODE> is a blocking system call that may not return, we wrap it in the standard <CODECLASS="literal">eval</CODE> block construct for timing out a blocking operation.<ACLASS="indexterm"NAME="ch17-idx-1000004745-0"></A><ACLASS="indexterm"NAME="ch17-idx-1000004745-1"></A><ACLASS="indexterm"NAME="ch17-idx-1000004745-2"></A><ACLASS="indexterm"NAME="ch17-idx-1000004745-3"></A><ACLASS="indexterm"NAME="ch17-idx-1000004745-4"></A></P></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch17-pgfId-824">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>,and <ACLASS="olink"HREF="../prog/ch03_005.htm"> <CODECLASS="literal">alarm</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="ch16_22.htm"TITLE="Timing Out an Operation">Recipe 16.21</A>; <ACLASS="xref"HREF="ch17_05.htm"TITLE="Setting Up a UDP Client">Recipe 17.4</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_05.htm"TITLE="17.4. Setting Up a UDP Client"><IMGSRC="../gifs/txtpreva.gif"ALT="Previous: 17.4. Setting Up a UDP Client"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_07.htm"TITLE="17.6. Using UNIX Domain Sockets"><IMGSRC="../gifs/txtnexta.gif"ALT="Next: 17.6. Using UNIX Domain Sockets"BORDER="0"></A></TD></TR><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228">17.4. Setting Up a UDP Client</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.6. Using UNIX Domain Sockets</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 + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -