📄 ch17_03.htm
字号:
<HTML><HEAD><TITLE>Recipe 17.2. Writing a TCP 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:22Z"><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_02.htm"TITLE="17.1. Writing a TCP Client"><LINKREL="next"HREF="ch17_04.htm"TITLE="17.3. Communicating over TCP"></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_02.htm"TITLE="17.1. Writing a TCP Client"><IMGSRC="../gifs/txtpreva.gif"ALT="Previous: 17.1. Writing a TCP 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_04.htm"TITLE="17.3. Communicating over TCP"><IMGSRC="../gifs/txtnexta.gif"ALT="Next: 17.3. Communicating over TCP"BORDER="0"></A></TD></TR></TABLE></DIV><DIVCLASS="sect1"><H2CLASS="sect1"><ACLASS="title"NAME="ch17-23871">17.2. Writing a TCP Server</A></H2><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch17-pgfId-260">Problem<ACLASS="indexterm"NAME="ch17-idx-1000004687-0"></A><ACLASS="indexterm"NAME="ch17-idx-1000004687-1"></A><ACLASS="indexterm"NAME="ch17-idx-1000004687-2"></A></A></H3><PCLASS="para">You want to write a server that waits for clients to connect over the network to a particular port.</P></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch17-pgfId-266">Solution</A></H3><PCLASS="para">This recipe assumes you're using the Internet to communicate. For TCP-like communication within a single Unix machine, see <ACLASS="xref"HREF="ch17_07.htm"TITLE="Using UNIX Domain Sockets">Recipe 17.6</A>.</P><PCLASS="para">Use the standard (as of 5.004) IO::Socket::INET class:</P><PRECLASS="programlisting">use IO::Socket;$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><PCLASS="para">Or, craft it by hand for better control:</P><PRECLASS="programlisting">use Socket;# make the socketsocket(SERVER, PF_INET, SOCK_STREAM, getprotobyname('tcp'));# so we can restart our server quicklysetsockopt(SERVER, SOL_SOCKET, SO_REUSEADDR, 1);# build up my socket address$my_addr = sockaddr_in($server_port, INADDR_ANY);bind(SERVER, $my_addr) or die "Couldn't bind to port $server_port : $!\n";# establish a queue for incoming connectionslisten(SERVER, SOMAXCONN) or die "Couldn't listen on port $server_port : $!\n";# accept and process connectionswhile (accept(CLIENT, SERVER)) { # do something with CLIENT}close(SERVER);</PRE></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch17-pgfId-348">Discussion</A></H3><PCLASS="para">Setting up a server is more complicated than being a client. The optional <CODECLASS="literal">listen</CODE> function tells the operating system how many pending, unanswered connections to queue up waiting for your server. The <CODECLASS="literal">setsockopt</CODE> function used in the Solution allows you to avoid waiting two minutes after killing your server before you restart it again (valuable in testing). The <CODECLASS="literal">bind</CODE> call registers your server with kernel so others may find you. Finally, <CODECLASS="literal">accept</CODE> takes the incoming connections one by one.</P><PCLASS="para">The numeric argument to <CODECLASS="literal">listen</CODE> is the number of un<CODECLASS="literal">accept</CODE>ed connections that the operating system should queue before clients start getting "connection refused" errors. Historically, the maximum <CODECLASS="literal">listen</CODE> value was 5, and even today, many operating systems silently limit this queue size to around 20. With busy web servers becoming commonplace, many vendors have increased this value. Your documented system maximum can be found in the SOMAXCONN constant from the Socket module.</P><PCLASS="para">The <CODECLASS="literal">accept</CODE><ACLASS="indexterm"NAME="ch17-idx-1000004696-0"></A> function takes two arguments: the filehandle to connect to the remote client and the server filehandle. It returns the client's port and IP address, as packed by <CODECLASS="literal">inet_ntoa</CODE>:</P><PRECLASS="programlisting">use Socket;while ($client_address = accept(CLIENT, SERVER)) { ($port, $packed_ip) = sockaddr_in($client_address); $dotted_quad = inet_ntoa($packed_ip); # do as thou wilt}</PRE><PCLASS="para">With the IO::Socket classes, <CODECLASS="literal">accept</CODE> is a method of the server filehandle:</P><PRECLASS="programlisting">while ($client = $server->accept()) { # ...}</PRE><PCLASS="para">If you call the <CODECLASS="literal">accept</CODE> method in list context, it returns the client socket and its address:</P><PRECLASS="programlisting">while (($client,$client_address) = $server->accept()) { # ...}</PRE><PCLASS="para">If no connection is waiting, your program blocks in the <CODECLASS="literal">accept</CODE> until a connection comes in. If you want to ensure that your <CODECLASS="literal">accept</CODE> won't block, use <ACLASS="indexterm"NAME="ch17-idx-1000005983-0"></A>non-blocking sockets:</P><PRECLASS="programlisting">use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK);$flags = fcntl(SERVER, F_GETFL, 0) or die "Can't get flags for the socket: $!\n";$flags = fcntl(SERVER, F_SETFL, $flags | O_NONBLOCK) or die "Can't set flags for the socket: $!\n";</PRE><PCLASS="para">Now, when you <CODECLASS="literal">accept</CODE> and nothing is waiting for you, <CODECLASS="literal">accept</CODE> will return <CODECLASS="literal">undef</CODE> and set <CODECLASS="literal">$!</CODE> to <CODECLASS="literal">EWOULDBLOCK</CODE>.</P><PCLASS="para">You might fear that when the return flags from F_GETFL are 0, that this would trigger the <CODECLASS="literal">die</CODE> just as a failure from <CODECLASS="literal">undef</CODE> would. Not so - as with <CODECLASS="literal">ioctl</CODE>, a non-error return from <CODECLASS="literal">fcntl</CODE> is mapped by Perl to the special value <ACLASS="indexterm"NAME="ch17-idx-1000005960-0"></A><ACLASS="indexterm"NAME="ch17-idx-1000005961-0"></A><CODECLASS="literal">"0</CODE> <CODECLASS="literal">but</CODE> <CODECLASS="literal">true"</CODE>. This special string is even exempt from the <BCLASS="emphasis.bold">-w</B> flag's pesky non-numeric warnings, so feel free to use it in your functions when you want to return a value that's numerically zero yet still true. It probably should have been <CODECLASS="literal">"0</CODE> <CODECLASS="literal">and</CODE> <CODECLASS="literal">sneaky"</CODE> instead.<ACLASS="indexterm"NAME="ch17-idx-1000004692-0"></A><ACLASS="indexterm"NAME="ch17-idx-1000004692-1"></A><ACLASS="indexterm"NAME="ch17-idx-1000004692-2"></A><ACLASS="indexterm"NAME="ch17-idx-1000004692-3"></A></P></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch17-pgfId-408">See Also</A></H3><PCLASS="para">The <ACLASS="olink"HREF="../prog/ch03_151.htm"> <CODECLASS="literal">socket</CODE></A>,<ACLASS="olink"HREF="../prog/ch03_007.htm"> <CODECLASS="literal">bind</CODE></A>,<ACLASS="olink"HREF="../prog/ch03_086.htm"><CODECLASS="literal">listen</CODE></A>, <ACLASS="olink"HREF="../prog/ch03_004.htm"><CODECLASS="literal">accept</CODE></A>, <ACLASS="olink"HREF="../prog/ch03_037.htm"><CODECLASS="literal">fcntl</CODE></A>, <ACLASS="olink"HREF="../prog/ch03_142.htm"><CODECLASS="literal">setsockopt</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); your system's <ICLASS="filename">fcntl </I>(2), <ICLASS="filename">socket </I>(2), <ICLASS="filename">setsockopt </I>(2) manpages (if you have them); the documentation for the standard Socket, IO::Socket, and Net::hostent modules; the section on <ACLASS="olink"HREF="../prog/ch06_02.htm#PERL2-CH-6-SECT-2.4.1">"Internet TCP Clients and Servers"</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>; <CITECLASS="citetitle">Beej's Guide to Network Programming</CITE> at <ACLASS="systemitem.url"HREF="http://www.ecst.csuchico.edu/~guide/net">http://www.ecst.csuchico.edu/~guide/net</A>; <ACLASS="xref"HREF="ch07_14.htm"TITLE="Reading from Many Filehandles Without Blocking">Recipe 7.13</A>; <ACLASS="xref"HREF="ch07_15.htm"TITLE="Doing Non-Blocking I/O">Recipe 7.14</A>; <ACLASS="xref"HREF="ch17_02.htm"TITLE="Writing a TCP Client">Recipe 17.1</A>; <ACLASS="xref"HREF="ch17_04.htm"TITLE="Communicating over TCP">Recipe 17.3</A>; <ACLASS="xref"HREF="ch17_08.htm"TITLE="Identifying the Other End of a Socket">Recipe 17.7</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_02.htm"TITLE="17.1. Writing a TCP Client"><IMGSRC="../gifs/txtpreva.gif"ALT="Previous: 17.1. Writing a TCP 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_04.htm"TITLE="17.3. Communicating over TCP"><IMGSRC="../gifs/txtnexta.gif"ALT="Next: 17.3. Communicating over TCP"BORDER="0"></A></TD></TR><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228">17.1. Writing a TCP 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.3. Communicating over TCP</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 + -