_chapter 3.htm

来自「Core Java 2(中文名称:JAVA 2 核心技术 卷二:高级特性)这是英」· HTM 代码 · 共 1,237 行 · 第 1/4 页

HTM
1,237
字号
<p>
<img alt="graphics/03fig06.gif" src="03fig06.gif" border="0" width="301" height="298"></p>
</center>
<p class="docText">The program simply sends the sequence of commands that we 
just discussed. It displays the commands that it sends to the SMTP server and 
the responses that it receives. Note that the communication with the mail server 
occurs in a separate thread so that the user interface thread is not blocked 
when the program tries to connect to the mail server. (See
<a class="docLink" href="_chapter%201.htm">Chapter 1</a> for more 
details on threads in Swing applications.)</p>
<h5 id="ch03list04" class="docExampleTitle">Example 3-4 MailTest.java</h5>
<pre>  1. import java.awt.*;
  2. import java.awt.event.*;
  3. import java.util.*;
  4. import java.net.*;
  5. import java.io.*;
  6. import javax.swing.*;
  7.
  8. /**
  9.    This program shows how to use sockets to send plain text
 10.    mail messages.
 11. */
 12. public class MailTest
 13. {
 14.    public static void main(String[] args)
 15.    {
 16.       JFrame frame = new MailTestFrame();
 17.       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 18.       frame.show();
 19.    }
 20. }
 21.
 22. /**
 23.    The frame for the mail GUI.
 24. */
 25. class MailTestFrame extends JFrame
 26. {
 27.    public MailTestFrame()
 28.    {
 29.       setSize(WIDTH, HEIGHT);
 30.       setTitle(&quot;MailTest&quot;);
 31.
 32.       getContentPane().setLayout(new GridBagLayout());
 33.
 34.       GridBagConstraints gbc = new GridBagConstraints();
 35.       gbc.fill = GridBagConstraints.HORIZONTAL;
 36.       gbc.weightx = 0;
 37.       gbc.weighty = 0;
 38.
 39.       gbc.weightx = 0;
 40.       add(new JLabel(&quot;From:&quot;), gbc, 0, 0, 1, 1);
 41.       gbc.weightx = 100;
 42.       from = new JTextField(20);
 43.       add(from, gbc, 1, 0, 1, 1);
 44.
 45.       gbc.weightx = 0;
 46.       add(new JLabel(&quot;To:&quot;), gbc, 0, 1, 1, 1);
 47.       gbc.weightx = 100;
 48.       to = new JTextField(20);
 49.       add(to, gbc, 1, 1, 1, 1);
 50.
 51.       gbc.weightx = 0;
 52.       add(new JLabel(&quot;SMTP server:&quot;), gbc, 0, 2, 1, 1);
 53.       gbc.weightx = 100;
 54.       smtpServer = new JTextField(20);
 55.       add(smtpServer, gbc, 1, 2, 1, 1);
 56.
 57.       gbc.fill = GridBagConstraints.BOTH;
 58.       gbc.weighty = 100;
 59.       message = new JTextArea();
 60.       add(new JScrollPane(message), gbc, 0, 3, 2, 1);
 61.
 62.       communication = new JTextArea();
 63.       add(new JScrollPane(communication), gbc, 0, 4, 2, 1);
 64.
 65.       gbc.weighty = 0;
 66.       JButton sendButton = new JButton(&quot;Send&quot;);
 67.       sendButton.addActionListener(new
 68.          ActionListener()
 69.          {
 70.             public void actionPerformed(ActionEvent evt)
 71.             {
 72.                new
 73.                   Thread()
 74.                   {
 75.                      public void run()
 76.                      {
 77.                         sendMail();
 78.                      }
 79.                   }.start();
 80.             }
 81.          });
 82.       JPanel buttonPanel = new JPanel();
 83.       buttonPanel.add(sendButton);
 84.       add(buttonPanel, gbc, 0, 5, 2, 1);
 85.    }
 86.
 87.    /**
 88.       Add a component to this frame.
 89.       @param c the component to add
 90.       @param gbc the grid bag constraints
 91.       @param x the grid bax column
 92.       @param y the grid bag row
 93.       @param w the number of grid bag columns spanned
 94.       @param h the number of grid bag rows spanned
 95.    */
 96.    private void add(Component c, GridBagConstraints gbc,
 97.       int x, int y, int w, int h)
 98.    {
 99.       gbc.gridx = x;
100.       gbc.gridy = y;
101.       gbc.gridwidth = w;
102.       gbc.gridheight = h;
103.       getContentPane().add(c, gbc);
104.    }
105.
106.    /**
107.       Sends the mail message that has been authored in the GUI.
108.    */
109.    public void sendMail()
110.    {
111.       try
112.       {
113.          Socket s = new Socket(smtpServer.getText(), 25);
114.
115.          out = new PrintWriter(s.getOutputStream());
116.          in = new BufferedReader(new
117.             InputStreamReader(s.getInputStream()));
118.
119.          String hostName
120.             = InetAddress.getLocalHost().getHostName();
121.
122.          receive();
123.          send(&quot;HELO &quot; + hostName);
124.          receive();
125.          send(&quot;MAIL FROM: &lt;&quot; + from.getText() +&quot;&gt;&quot;);
126.          receive();
127.          send(&quot;RCPT TO: &lt;&quot; + to.getText() +&quot;&gt;&quot;);
128.          receive();
129.          send(&quot;DATA&quot;);
130.          receive();
131.          StringTokenizer tokenizer = new StringTokenizer(
132.             message.getText(), &quot;\n&quot;);
133.          while (tokenizer.hasMoreTokens())
134.             send(tokenizer.nextToken());
135.          send(&quot;.&quot;);
136.          receive();
137.          s.close();
138.       }
139.       catch (IOException exception)
140.       {
141.          communication.append(&quot;Error: &quot; + exception);
142.       }
143.    }
144.
145.    /**
146.       Sends a string to the socket and echoes it in the
147.       communication text area.
148.       @param s the string to send.
149.    */
150.    public void send(String s) throws IOException
151.    {
152.       communication.append(s);
153.       communication.append(&quot;\n&quot;);
154.       out.print(s);
155.       out.print(&quot;\r\n&quot;);
156.       out.flush();
157.    }
158.
159.    /**
160.       Receives a string from the socket and displays it
161.       in the communication text area.
162.    */
163.    public void receive() throws IOException
164.    {
165.       String line = in.readLine();
166.       if (line != null)
167.       {
168.          communication.append(line);
169.          communication.append(&quot;\n&quot;);
170.       }
171.    }
172.
173.    private BufferedReader in;
174.    private PrintWriter out;
175.    private JTextField from;
176.    private JTextField to;
177.    private JTextField smtpServer;
178.    private JTextArea message;
179.    private JTextArea communication;
180.
181.    public static final int WIDTH = 300;
182.    public static final int HEIGHT = 300;
183. }
</pre>
<h3 class="docSection1Title" id="c3s4">Advanced Socket Programming</h3>
<h4 class="docSection2Title" id="ch03lev2sec2">Socket timeouts</h4>
<p class="docText">In real-life programs, you don't just want to read from a 
socket, because the read methods will block until data is available. If the host 
is unreachable, then your application waits for a long time, and you are at the 
mercy of the underlying operating system to time out eventually.</p>
<p class="docText">Instead, you should decide what timeout value is reasonable 
for your particular application. Then, call the <tt>setSoTimeout</tt> method to 
set a timeout value (in milliseconds).</p>
<pre>Socket s = new Socket(. . .);
s.setSoTimeout(10000); // time out after 10 seconds
</pre>
<p class="docText">If the timeout value has been set for a socket, then all 
subsequent read operations throw an <tt>InterruptedIOException</tt> when the 
timeout has been reached before input is available. You can catch that exception 
and react to the timeout.</p>
<pre>try
{
   String line
   while ((String line = in.readLine()) != null)
   {
      <span class="docEmphasis">process</span> line
   }
}
catch (InterruptedIOException exception)
{
   <span class="docEmphasis">react to timeout</span>
}
</pre>
<p class="docText">There is one additional timeout issue that you need to 
address. The constructor</p>
<pre>Socket(String host, int port)
</pre>
<p class="docText">can block indefinitely until an initial connection to the 
host is established.</p>
<p class="docText">As of SDK 1.4, you can overcome this problem by first 
constructing an unconnected socket and then connecting it with a timeout:</p>
<pre>Socket s = new Socket();
s.connect(new InetSocketAddress(host, port), timeout);
</pre>
<div class="docNote">
  <p class="docNoteTitle">TIP</p>
  <table cellSpacing="0" cellPadding="1" width="90%" border="0">
    <tr>
      <td vAlign="top" width="60">
      <img alt="graphics/tip.gif" src="tip.gif" align="left" border="0" width="54" height="50"><br>
&nbsp;</td>
      <td vAlign="top">
      <p class="docText">If you use an older version of the SDK, you need to 
      construct the socket in a separate thread and wait for that thread to 
      either complete or time out.</p>
      <pre>Socket socket = null;
Thread t = new Thread()
   {
      public void run()
      {
         try
         {
            socket = new Socket(host, port);
         }
         catch (IOException exception)
         {
         }
      }
   };

t.start();
try
{
   t.join(timeout);
}
catch (InterruptedException exception)
{
}
</pre>
      <p class="docText">The <tt>join</tt> method returns when the thread has 
      completed or when the timeout has expired, whichever happens first. If the
      <tt>socket</tt> variable is not <tt>null</tt>, then the socket has been 
      successfully opened within the allotted time.</td>
    </tr>
  </table>
</div>
<h4 class="docSection2Title" id="ch03lev2sec3">Half-Close</h4>
<p class="docText">When a client program sends a request to the server, the 
server needs to be able to determine when the end of the request occurs. For 
that reason, many Internet protocols (such as SMTP) are line-oriented. Other 
protocols contain a header that specifies the size of the request data. 
Otherwise, indicating the end of the request data is harder than writing data to 
a file. With a file, you'd just close the file at the end of the data. But if 
you close a socket, then you immediately disconnect from the server.</p>
<p class="docText">The <span class="docEmphasis">half-close</span> overcomes 
this problem. You can close the output stream of a socket, thereby indicating to 
the server the end of the request data, but keep the input stream open so that 
you can read the response.</p>
<p class="docText">The client side looks like this:</p>
<pre>Socket socket = new Socket(host, port);
BufferedReader reader = new BufferedReader(
   new InputStreamReader(socket.getInputStream()));
PrintWriter writer = new PrintWriter(
   socket.getOutputStream());
// send request data
writer.print(. . .);
writer.flush();
socket.shutdownOutput();
// now socket is half closed
// read response data
String line;
while ((line = reader.readLine()) != null)
   . . .
socket.close();
</pre>
<p class="docText">The server side simply reads input until the end of the input 
stream is reached.</p>
<p class="docText">Of course, this protocol is only useful for one-shot services 
such as HTTP where the client connects, issues a request, catches the response, 

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?