📄 ch18.htm
字号:
</TD></TR>
</TABLE>
</CENTER>
<P>
<P>
The second line of this short example creates a full Internet
socket address using the <TT>pack()</TT>
fuNCtion. This is another complicated topic that I will sidestep.
As long as you know the port number and the server's address,
you can simply plug those values into the example code and not
worry about the rest. The important part of the example is the
"\0\0\0\0" string. This string holds the four numbers
that make up the dotted decimal Internet address. If you already
know the dotted decimal address, convert each number to octal
and replace the appropriate \0 in the string.
<P>
If you know the symbolic name of the server instead of the dotted
decimal address, use the following line to create the packed Internet
address:
<BLOCKQUOTE>
<PRE>
$internetPackedAddress = pack('S n A4 x8', AF_INET(), $port,
gethostbyname('www.remotehost.com'));
</PRE>
</BLOCKQUOTE>
<P>
After the socket has been created and an address has been bound
to it, you need to create a queue for the socket. This is done
with the <TT>listen()</TT> fuNCtion.
The <TT>listen()</TT> call looks like
this:
<BLOCKQUOTE>
<PRE>
listen(SOCKET, 5) or die("listen: $!");
</PRE>
</BLOCKQUOTE>
<P>
This <TT>listen()</TT> statement will
create a queue that can handle 5 remote attempts to connect. The
sixth attempt will fail with an appropriate error code.
<P>
Now that the socket exists, has an address, and has a queue, your
program is ready to begin a conversation using the <TT>accept()</TT>
fuNCtion. The <TT>accept()</TT> fuNCtion
makes a copy of the socket and starts a conversation with the
new socket. The original socket is still available and able to
accept connections. You can use the <TT>fork()</TT>
fuNCtion, in UNIX, to create child processes to handle multiple
conversations. The normal <TT>accept()</TT>
fuNCtion call looks like this:
<BLOCKQUOTE>
<PRE>
$addr = accept(NEWSOCKET, SOCKET) or die("accept: $!");
</PRE>
</BLOCKQUOTE>
<P>
Now that the conversation has been started, use <TT>print()</TT>,
<TT>send()</TT>, <TT>recv()</TT>,
<TT>read()</TT>, or <TT>write()</TT>
to hold the conversation. The examples later in the chapter show
how the conversations are held.
<H3><A NAME="TheClientSideofaConversation">
The Client Side of a Conversation</A></H3>
<P>
Client programs will use <TT>socket()</TT>
to create a socket and <TT>connect()</TT>
to initiate a connection to a server's socket. Then input/output
fuNCtions are used to hold a conversation. And the <TT>close()</TT>
fuNCtion closes the socket.
<P>
The <TT>socket()</TT> call for the
client program is the same as that used in the server:
<BLOCKQUOTE>
<PRE>
$tcpProtocolNumber = getprotobyname('tcp') || 6;
socket(SOCKET, PF_INET(), SOCK_STREAM(), $tcpProtocolNumber)
or die("socket: $!");
</PRE>
</BLOCKQUOTE>
<P>
After the socket is created, the <TT>connect()</TT>
fuNCtion is called like this:
<BLOCKQUOTE>
<PRE>
$port = 20001;
$internetPackedAddress = pack('Sna4x8', AF_INET(), $port, "\0\0\0\0");
connect(SOCKET, $internetPackedAddress) or die("connect: $!");
</PRE>
</BLOCKQUOTE>
<P>
The packed address was explained in "The Server Side of a
Conversation." The <TT>SOCKET</TT>
parameter has no relation to the name used on the server machine.
I use <TT>SOCKET</TT> on both sides
for convenieNCe.
<P>
The <TT>connect()</TT> fuNCtion is
a <I>blocking</I> fuNCtion. This means that it will wait until
the connection is completed. You can use the <TT>select()</TT>
fuNCtion to set non-blocking mode, but you'll need to look in
the UNIX documentation to find out how. It's a bit complicated
to explain here.
<P>
After the connection is made, you use the normal input/output
fuNCtions or the <TT>send()</TT> and
<TT>recv()</TT> fuNCtions to talk
with the server.
<P>
The rest of the chapter will be devoted to looking at examples
of specific protocols. Let's start out by looking at the time
service.
<H2><A NAME="UsingtheTimeService"><FONT SIZE=5 COLOR=#FF0000>
Using the Time Service</FONT></A></H2>
<P>
It is very important that all computers on a given network report
the same time. This allows backups and other regularly scheduled
events to be automated. Instead of manually adjusting the time
on every computer in the network, you can designate a time server.
The other computers can use the time server to determine the correct
time and adjust their own clocks accordingly.
<P>
Listing 18.1 contains a program that can retrieve the time from
any time server in the world. Modify the example to access your
own time server by setting the <TT>$remoteServer</TT>
variable to your server's symbolic name.
<P>
<IMG SRC="pseudo.gif" tppabs="http://cheminf.nankai.edu.cn/~eb~/Perl%205%20By%20Example/pseudo.gif" BORDER=1 ALIGN=RIGHT><p>
<BLOCKQUOTE>
<I>Turn on the warning compiler option.<BR>
Load the </I><TT><I>Socket</I></TT><I>
module.<BR>
Turn on the strict pragma.<BR>
Initialize the </I><TT><I>$remoteServer</I></TT><I>
to the symbolic name of the time server.<BR>
Set a variable equal to the number of seconds in 70 years.<BR>
Initialize a buffer variable, </I><TT><I>$buffer</I></TT><I>.
<BR>
Declare </I><TT><I>$socketStructure</I></TT><I>.
<BR>
Declare </I><TT><I>$serverTime</I></TT><I>.
<BR>
Get the tcp protocol and time port numbers, provide a default
in case the </I><TT><I>getprotobyname()</I></TT><I>
and </I><TT><I>getservbyname()</I></TT><I>
fuNCtions are notimplemented.<BR>
Initialize </I><TT><I>$serverAddr</I></TT><I>
with the Internet address of the time server.<BR>
Display the current time on the local machine, also called the
localhost.<BR>
Create a socket using the standard parameters.<BR>
Initialize </I><TT><I>$packedFormat</I></TT><I>
with format specifiers.<BR>
Connect the local socket to the remote socket that is providing
the time service.<BR>
Read the server's time as a 4 byte value. <BR>
Close the local socket.<BR>
Unpack the network address from a long (4 byte) value into a string
value.<BR>
Adjust the server time by the number of seconds in 70 years.<BR>
Display the server's name, the number of seconds differeNCe between
the remote time and the local time.<BR>
Declare the </I><TT><I>ctime()</I></TT><I>
fuNCtion.<BR>
Return a string reflecting the time represented by the parameter.</I>
</BLOCKQUOTE>
<HR>
<BLOCKQUOTE>
<B>Listing 18.1 18LST01.PL-Getting the Time from a
Time Service<BR>
</B>
</BLOCKQUOTE>
<BLOCKQUOTE>
<PRE>
#!/usr/bin/perl -w
use Socket;
use strict;
my($remoteServer) = 'saturn.planet.net';
my($secsIn70years) = 2208988800;
my($buffer) = '';
my($socketStructure);
my($serverTime);
my($proto) = getprotobyname('tcp') || 6;
my($port) = getservbyname('time', 'tcp') || 37;
my($serverAddr) = (gethostbyname($remoteServer))[4];
printf("%-20s %8s %s\n", "localhost", 0, ctime(time()));
socket(SOCKET, PF_INET, SOCK_STREAM, $proto)
or die("socket: $!");
my($packFormat) = 'S n a4 x8'; # Windows 95, SunOs 4.1+
#my($packFormat) = 'S n c4 x8'; # SunOs 5.4+ (Solaris 2)
connect(SOCKET, pack($packFormat, AF_INET(), $port, $serverAddr))
or die("connect: $!");
read(SOCKET, $buffer, 4);
close(SOCKET);
$serverTime = unpack("N", $buffer);
$serverTime -= $secsIn70years;
printf("%-20s %8d %s\n", $remoteServer, $serverTime - time,
ctime($serverTime));
sub ctime {
return(scalar(localtime($_[0])));
}
</PRE>
</BLOCKQUOTE>
<HR>
<P>
Each operating system will have a different method to update the
local time. So I'll leave it in your hands to figure how to do
that.
<P>
The next section is devoted to sending mail. First the protocol
will be explained and then you will see a Perl script that can
send a mail message.
<H2><A NAME="SendingMailSMTP"><FONT SIZE=5 COLOR=#FF0000>
Sending Mail (SMTP)</FONT></A></H2>
<P>
Before you send mail, the entire message needs to be composed.
You need to know where it is going, who gets it, and what the
text of the message is. When this information has been gathered,
you begin the process of transferring the information to a mail
server.<BR>
<p>
<CENTER>
<TABLE BORDERCOLOR=#000000 BORDER=1 WIDTH=80%>
<TR><TD><B>Note</B></TD></TR>
<TR><TD>
<BLOCKQUOTE>
The mail service will be listening for your connection on TCP port 25. But this information will not be important until you see some Perl code later in the chapter.</BLOCKQUOTE>
</TD></TR>
</TABLE>
</CENTER>
<P>
<P>
The message that you prepare can only use alphanumeric characters.
If you need to send binary information (like files), use the MIME
protocol. The details of the MIME protocol can be found at the
<B>http://ds.internic.net/ds/dspg0intdoc.html</B> Web site.
<P>
SMTP uses several commands to communicate with mail servers. These
commands are described in Table 18.3. The commands are not case-insensitive,
which means you can use either Mail or MAIL. However, remember
that mail addresses are case-sensitive.<BR>
<CENTER><B>Table 18.3 The SMTP Command Set</B></CENTER>
<p>
<CENTER>
<TABLE BORDERCOLOR=#000000 BORDER=1 WIDTH=80%>
<TR><TD WIDTH=133><CENTER><I>Command</I></CENTER></TD><TD WIDTH=457><I>Description</I>
</TD></TR>
<TR><TD COLSPAN=2 WIDTH=590><B>Basic Commands</B></TD></TR>
<TR><TD WIDTH=133><CENTER><TT>HELO</TT></CENTER>
</TD><TD WIDTH=457>Initiates a conversation with the mail server. When using this command you can specify your domain name so that the mail server knows who you are. For example, <TT>HELO mailhost2. planet.net</TT>.
</TD></TR>
<TR><TD WIDTH=133><CENTER><TT>MAIL</TT></CENTER>
</TD><TD WIDTH=457>Indicates who is sending the mail. For example, <TT>MAIL FROM: <medined@planet.net></TT>. Remember this is not <I>your</I> name, it's the name of the person who is sending the mail message. Any returned mail will be sent back to
this address.
</TD></TR>
<TR><TD WIDTH=133><CENTER><TT>RCPT</TT></CENTER>
</TD><TD WIDTH=457>Indicates who is recieving the mail. For example, <TT>RCPT TO: <rolf@earthdawn.com></TT>. You can indicate more than one user by issuing multiple <TT>RCPT</TT> commands.
</TD></TR>
<TR><TD WIDTH=133><CENTER><TT>DATA</TT></CENTER>
</TD><TD WIDTH=457>Indicates that you are about to send the text (or body) of the message. The message text must end with the following five letter sequeNCe: "\r\n.\r\n."
</TD></TR>
<TR><TD WIDTH=133><CENTER><TT>QUIT</TT></CENTER>
</TD><TD WIDTH=457>Indicates that the conversation is over.</TD>
</TR>
<TR><TD COLSPAN=2 WIDTH=590><B>AdvaNCed Commands (see RFC 821 for details)</B>
</TD></TR>
<TR><TD WIDTH=133><CENTER><TT>EXPN</TT></CENTER>
</TD><TD WIDTH=457>Indicates that you are using a mailing list.
</TD></TR>
<TR><TD WIDTH=133><CENTER><TT>HELP</TT></CENTER>
</TD><TD WIDTH=457>Asks for help from the mail server.</TD></TR>
<TR><TD WIDTH=133><CENTER><TT>NOOP</TT></CENTER>
</TD><TD WIDTH=457>Does nothing other than get a reponse from the mail server.
</TD></TR>
<TR><TD WIDTH=133><CENTER><TT>RSET</TT></CENTER>
</TD><TD WIDTH=457>Aborts the current conversation.</TD></TR>
<TR><TD WIDTH=133><CENTER><TT>SEND</TT></CENTER>
</TD><TD WIDTH=457>Sends a message to a user's terminal instead of a mailbox.
</TD></TR>
<TR><TD WIDTH=133><CENTER><TT>SAML</TT></CENTER>
</TD><TD WIDTH=457>Sends a message to a user's terminal and to a user's mailbox.
</TD></TR>
<TR><TD WIDTH=133><CENTER><TT>SOML</TT></CENTER>
</TD><TD WIDTH=457>Sends a message to a user's terminal if they are logged on; otherwise, sends the message to the user's mailbox.
</TD></TR>
<TR><TD WIDTH=133><CENTER><TT>TURN</TT></CENTER>
</TD><TD WIDTH=457>Reverses the role of client and server. This might be useful if the client program can also act as a server and needs to receive mail from the remote computer.
</TD></TR>
<TR><TD WIDTH=133><CENTER><TT>VRFY</TT></CENTER>
</TD><TD WIDTH=457>Verifies the existeNCe and user name of a given mail address. This command is not implemented in all mail servers. And it can be blocked by firewalls.
</TD></TR>
</TABLE>
</CENTER>
<P>
<P>
Every command will receive a reply from the mail server in the
form of a three digit number followed by some text describing
the reply. For example, <TT>250 OK</TT>
or <TT>500 Syntax error, command unrecognized</TT>.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -