📄 tij0166.html
字号:
<html><body>
<table width="100%"><tr>
<td>
<a href="http://www.bruceeckel.com/javabook.html">Bruce Eckel's Thinking in Java</a>
</td>
<td align="right">
<a href="tij_c.html">Contents</a> | <a href="tij0165.html">Prev</a> | <a href="tij0167.html">Next</a>
</td>
</tr></table>
<hr>
<H2 ALIGN=LEFT>
Datagrams<P><A NAME="Index2661"></A><A NAME="Index2662"></A></H2>
<DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">The
examples you’ve seen so far use the <A NAME="Index2663"></A><A NAME="Index2664"></A><A NAME="Index2665"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>Transmission
Control Protocol
</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
(TCP, also known as <A NAME="Index2666"></A><A NAME="Index2667"></A><A NAME="Index2668"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>stream-based
sockets
</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">),
which is designed for ultimate reliability and guarantees that the data will
get there. It allows retransmission of lost data, it provides multiple paths
through different routers in case one goes down, and bytes are delivered in the
order they are sent. All this control and reliability comes at a cost: TCP has
a high overhead.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">There’s
a second protocol, called <A NAME="Index2669"></A><A NAME="Index2670"></A><A NAME="Index2671"></A><A NAME="Index2672"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>User
Datagram Protocol
</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
(UDP), which doesn’t guarantee that the packets will be delivered and
doesn’t guarantee that they will arrive in the order they were sent.
It’s called an “<A NAME="Index2673"></A><A NAME="Index2674"></A>unreliable
protocol” (TCP is a <A NAME="Index2675"></A><A NAME="Index2676"></A>“reliable
protocol”), which sounds bad, but because it’s much faster it can
be useful. There are some applications, such as an audio signal, in which it
isn’t so critical if a few packets are dropped here or there but speed is
vital. Or consider a time-of-day server, where it really doesn’t matter
if one of the messages is lost. Also, some applications might be able to fire
off a UDP message to a server and can then assume, if there is no response in a
reasonable period of time, that the message was lost.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">The
support for datagrams in Java has the same feel as its support for TCP sockets,
but there are significant differences. With datagrams, you put a <A NAME="Index2677"></A><A NAME="Index2678"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>DatagramSocket</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
on both the client and server, but there is no analogy to the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>ServerSocket</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
that waits around for a connection. That’s because there is no
“connection,” but instead a datagram just shows up. Another
fundamental difference is that with TCP sockets, once you’ve made the
connection you don’t need to worry about who’s talking to whom
anymore; you just send the data back and forth through conventional streams.
However, with datagrams, the datagram packet must know where it came from and
where it’s supposed to go. That means you must know these things for each
datagram packet that you load up and ship off.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">A
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>DatagramSocket</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
sends and receives the packets, and the <A NAME="Index2679"></A><A NAME="Index2680"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>DatagramPacket</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
contains the information. When you’re receiving a datagram, you need only
provide a buffer in which the data will be placed; the information about the
Internet address and port number where the information came from will be
automatically initialized when the packet arrives through the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>DatagramSocket</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
So the constructor for a
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>DatagramPacket
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">to
receive datagrams is:
</FONT><P></DIV><DIV ALIGN=LEFT><TT><FONT FACE="Courier New" SIZE=3 COLOR="Black">DatagramPacket(buf,
buf.length)
</FONT></TT><P></DIV><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">in
which
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>buf
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">is
an array of
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>byte</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Since
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>buf</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is an array, you might wonder why the constructor couldn’t figure out the
length of the array on its own. I wondered this, and can only guess that
it’s a throwback to C-style programming, in which of course arrays
can’t tell you how big they are.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">You
can reuse a receiving datagram; you don’t have to make a new one each
time. Every time you reuse it, the data in the buffer is overwritten.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">The
maximum size of the buffer is restricted only by the allowable datagram packet
size, which limits it to slightly less than 64Kbytes. However, in many
applications you’ll want it to be much smaller, certainly when
you’re sending data. Your chosen packet size depends on what you need for
your particular application.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">When
you send a datagram, the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>DatagramPacket</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
must contain not only the data, but also the Internet address and port where it
will be sent. So the constructor for an outgoing
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>DatagramPacket</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is:
</FONT><P></DIV><DIV ALIGN=LEFT><TT><FONT FACE="Courier New" SIZE=3 COLOR="Black">DatagramPacket(buf,
length, inetAddress, port)
</FONT></TT><P></DIV><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">This
time,
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>buf</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
(which is a
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>byte
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">array)
already contains the data that you want to send out. The
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>length</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
might be the length of
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>buf</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
but it can also be shorter, indicating that you want to send only that many
bytes. The other two arguments are the Internet address where the packet is
going and the destination port within that machine.
</FONT><A NAME="fnB64" HREF="#fn64">[64]</A><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">You
might think that the two constructors create two different objects: one for
receiving datagrams and one for sending them. Good OO design would suggest that
these should be two different classes, rather than one class with different
behavior depending on how you construct the object. This is probably true, but
fortunately the use of
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>DatagramPacket</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">s
is simple enough that you’re not tripped up by the problem, as you can
see in the following example. This example is similar to the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>MultiJabberServer</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>MultiJabberClient</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
example for TCP sockets. Multiple clients will send datagrams to a server,
which will echo them back to the same client that sent the message.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">To
simplify the creation of a
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>DatagramPacket</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
from a
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>String</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and vice-versa, the example begins with a utility class,
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Dgram</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
to do the work for you:
</FONT><P></DIV>
<font color="#990000"><PRE><font color="#009900">//: Dgram.java</font>
<font color="#009900">// A utility class to convert back and forth</font>
<font color="#009900">// Between Strings and DataGramPackets.</font>
<font color="#0000ff">import</font> java.net.*;
<font color="#0000ff">public</font> <font color="#0000ff">class</font> Dgram {
<font color="#0000ff">public</font> <font color="#0000ff">static</font> DatagramPacket toDatagram(
String s, InetAddress destIA, <font color="#0000ff">int</font> destPort) {
<font color="#009900">// Deprecated in Java 1.1, but it works:</font>
<font color="#0000ff">byte</font>[] buf = <font color="#0000ff">new</font> <font color="#0000ff">byte</font>[s.length() + 1];
s.getBytes(0, s.length(), buf, 0);
<font color="#009900">// The correct Java 1.1 approach, but it's</font>
<font color="#009900">// Broken (it truncates the String):</font>
<font color="#009900">// byte[] buf = s.getBytes();</font>
<font color="#0000ff">return</font> <font color="#0000ff">new</font> DatagramPacket(buf, buf.length,
destIA, destPort);
}
<font color="#0000ff">public</font> <font color="#0000ff">static</font> String toString(DatagramPacket p){
<font color="#009900">// The Java 1.0 approach:</font>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -