我爱电脑技术论坛's Archiver

bbs23 发表于 2008-3-31 07:42

在Java编程语言中实现UDP协议编程的方法

什么是UDP协议
"Tz'm}TO
4{eA6R"?(s3c
h6iT+Y8E? UDP协议的全称是用户数据报,在网络中它与TCP协议一样用于处理数据包。在OSI模型中,在第四层——传输层,处于IP协议的上一层。UDP有不提供数据报分组、组装和不能对数据包的排序的缺点,也就是说,当报文发送之后,是无法得知其是否安全完整到达的。 pQ#T~4cJ

9mq4yR0c0Q#V ]anI(jn
为什么要使用UDP |$B/T S;[~x_'H:^n/U
M(j1u y's2n%D(M
![(L0Lw*~ L
在选择使用协议的时候,选择UDP必须要谨慎。在网络质量令人不十分满意的环境下,UDP协议数据包丢失会比较严重。但是由于UDP的特性:它不属于连接型协议,因而具有资源消耗小,处理速度快的优点,所以通常音频、视频和普通数据在传送时使用UDP较多,因为它们即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。比如我们聊天用的ICQ和OICQ就是使用的UDP协议。 1R"W;F2c%[!y$Nr

!`9?R'tm$U3k(Gx 9d|@.^zyk3c
在Java中操纵UDP 0AA!R&c P\(F#x U P%]
*`s!Y$h,Vd1k+C X

8m C,CO^ q(a3Si 使用位于JDK中Java.net包下的DatagramSocket和DatagramPacket类,可以非常方便地控制用户数据报文。 *e\CZ8V,N4z

-y*rm%k;_3ns Ki7m EZoCF `
在描述它们之前,必须了解位于同一个位置的InetAddress类。InetAddress实现了Java.io. Serializable接口,不允许继承。它用于描述和包装一个Internet IP地址,通过三个方法返回InetAddress实例: 4M'x L)_Q~
2kK%M0^xny3Vn

Lm0E|4~)l:tmrg,X getLocalhost():返回封装本地地址的实例。 $LW!}dhC+n7m

?yruH|8WK`"Y#e
F!w)j-Hp9T getAllByName(String host):返回封装Host地址的InetAddress实例数组。 L5_uo,v*G
6we8pbau
8pb ^.H!{N!Zk
getByName(String host):返回一个封装Host地址的实例。其中,Host可以是域名或者是一个合法的IP地址。
B o&K B@{y5u ;a3`(V'XF.u P
F p&\'KOxR
DatagramSocket类用于创建接收和发送UDP的Socket实例。和Socket类依赖SocketImpl类一样,DatagramSocket类的实现也依靠专门为它设计的DatagramScoketImplFactory类。DatagramSocket类有3个构建器:
MA`4_+_T2Hq ?*Z+i {D } d/G
z0Z/l%K5`.hJD[{
DatagramSocket():创建实例。这是个比较特殊的用法,通常用于客户端编程,它并没有特定监听的端口,仅仅使用一个临时的。 TR(Qb0x[y

'YQd)|;l#R?@K*i
AQ8|;k.cMy*KWt DatagramSocket(int port):创建实例,并固定监听Port端口的报文。
%G{&I,a$oO,_7K R3o9g1PKm5g9\~
OicD d/|'O6Js
DatagramSocket(int port, InetAddress localAddr):这是个非常有用的构建器,当一台机器拥有多于一个IP地址的时候,由它创建的实例仅仅接收来自LocalAddr的报文。 4L Y iur*fS)o AO-w

j"ki?'Nev
+^$d@ N1Ks ?L 值得注意的是,在创建DatagramSocket类实例时,如果端口已经被使用,会产生一个SocketException的异常抛出,并导致程序非法终止,这个异常应该注意捕获。DatagramSocket类最主要的方法有4个: f*V,|k@+d)`\:X&h
^{ a R^%zd_+S
s)@Nrz[ EH@
Receive(DatagramPacket d):接收数据报文到d中。receive方法产生一个“阻塞”。 !]y&jH2~'e&s
+Px#r f#CNc
)s^ Q%XCX7k
Send(DatagramPacket d):发送报文d到目的地。
6I'v-xb%h-r3R;K@0\
b+D Me*@E-[;V2]c
GnoZQnJi SetSoTimeout(int timeout):设置超时时间,单位为毫秒。 7gm Qr4gp [ js0f

2|V H'~#GawHm U7m.n
0g8QeT*Ko}(J/dI Close():关闭DatagramSocket。在应用程序退出的时候,通常会主动释放资源,关闭Socket,但是由于异常地退出可能造成资源无法回收。所以,应该在程序完成时,主动使用此方法关闭Socket,或在捕获到异常抛出后关闭Socket。
8v!oM9PFz
CE+A$L6{ic.y Nrd E8H m9B
“阻塞”是一个专业名词,它会产生一个内部循环,使程序暂停在这个地方,直到一个条件触发。 BA/Ap*Px2uc:i7MU4n
^#Qq-^o$cz

q{ZxYR?-i DatagramPacket类用于处理报文,它将Byte数组、目标地址、目标端口等数据包装成报文或者将报文拆卸成Byte数组。应用程序在产生数据包是应该注意,TCP/IP规定数据报文大小最多包含65507个,通常主机接收548个字节,但大多数平台能够支持8192字节大小的报文。DatagramPacket类的构建器共有4个:
e,X,W[h p8\ lSL[u
c/n,UOgE
DatagramPacket(byte[] buf, int length, InetAddress addr, int port):从Buf数组中,取出Length长的数据创建数据包对象,目标是Addr地址,Port端口。 }K]hsN!v
gnS_e;H
r^q'^.n!lv%P"^ U w
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port):从Buf数组中,取出Offset开始的、Length长的数据创建数据包对象,目标是Addr地址,Port端口。
6P%q3^{;b(h0iJ
a8r Qi B9o MV0H"fs g 5OIN o5U+W0~5pm
DatagramPacket(byte[] buf, int offset, int length):将数据包中从Offset开始、Length长的数据装进Buf数组。
,waR!P,i5B3q U/v&O+v !E K N]6my!M

X U n xENd&bU DatagramPacket(byte[] buf, int length):将数据包中Length长的数据装进Buf数组。 q$?#Wb`g}}(Pn`
vJ;x K dA"I7|

5v;l,g` Z/Wh DatagramPacket类最重要的方法就是getData()了,它从实例中取得报文的Byte数组编码。
:}Nl`}[S3qZ 6[9o0i%Yt6?D^ W
H_2b ~$bh*C
简单的实例说明 *Oj Z A)N.{
4U [\;T(W JAt]
#@4~ N\S;\Cm
{接收数据的服务器} #S3L3r"s$X-WL8O4w.mE
2N:S Q(en+rv6a
byte[] buf = new byte[1000];
7K^G#v X@%yIk*U;}P !M(~ adeq
DatagramSocket ds = new DatagramSocket(12345); a"I"Qq1m

0}vY&dVprO-Y&eK //开始监视12345端口 ]n K(vz
P;n"n(O@{.x)\o
DatagramPacket ip = new DatagramPacket(buf, buf.length); %`Hg{LT([-M c@f

[_&~w/K7[f'y6~?u //创建接收数据报的实例
_ [xFL$C G
;Xj3`2kJv4u'\'fO2y while (true) ;Hxv@,]%t8m0h

)@#wI*K1I/J Z8V I { 9? As)mr0U#b

8K.D4T"Q5|E ds.receive(ip); q1Gk[iA.Ln]"k0u

6X;s h/D6f/Ye //阻塞,直到收到数据报后将数据装入IP中
;s(W J%jg rsk*sa6b3[ 2^A,]r7YW%@rK\
System.out.println(new String(buf));
$g A~8NT'|/dr ~.FhlZ0Oyx
}
9c Q&w do8_O [~;f!V)pB
{发送数据的客户端} 'dLJ@;j&l2@$X
9K%m;AO8m
InetAddress target = InetAddress.getByName(“[url]www.xxx.com[/url]“); P y|pE-\imi

M ~n7s_z_.^?L //得到目标机器的地址实例 -O-v$\UnT;@N)x
B1c y8YoZy
DatagramSocket ds = new DatagramSocket(9999);
-C(K,b,]/|5{ T'h'~
9iB;]6Ai:a //从9999端口发送数据报
Ki0AQ6\ (rJp%q0Ph o%{
String hello = “Hello, I am come in!”; j0W.sJ+r s8O&w*C5_w

Sq6\ W6J0n(|&M //要发送的数据 %OP,a"he6Ep|)j(G w

+C vtY9b!Dg.hT byte[] buf = hello.getBytes();
"r&J&BcR7j8Hx!pT
qd-e&H$N3zO //将数据转换成Byte类型
5P{P^O.D AP Q6j,n8i'L
op = new DatagramPacket(buf, buf.length, target, 12345);
4X_UW4Ul2]\
;ig\;Z i //将BUF缓冲区中的数据打包 $ka!T4z3s/@9w.Uf6k

-L%\'@j'W%{RW9hL ds.send(op);
R-f A` ~
2d:W,o(z&Y {8c| //发送数据
0u$J4rd6XEn*w*a
u}\u^Mj(Fh ds.close();
Ba W|7Ysi #z5_?p^J:C:z
//关闭连接

页: [1]

Powered by Discuz! Archiver 6.1.0  © 2001-2007 Comsenz Inc.