版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、Java网络编程精解,作者:孙卫琴 参考书籍: 技术支持网址:,第8章 基于UDP的数据报和套接字,参考Java网络编程精解的第8章,8.1 UDP协议简介 8.2 DatagramPacket类 8.3 DatagramSocket类 8.4 DatagramChannel类 8.5 组播Socket,第8章 基于UDP的数据报和套接字,UDP(User Datagram Protocol,用户数据报协议)是传输层的另一种协议,它比TCP具有更快的传输速度,但是不可靠。 UDP发送的数据单元称为UDP数据报。当网络传输UDP数据报时,无法保证数据报一定到
2、达目的地,也无法保证各个数据报按发送的顺序到达目的地。 当发送方先发送包含字符串“hello”的数据报,再发送包含字符串“everyone”的数据报,接收方有可能先接收到字符串 “everyone”,再接收到字符串“hello”;也有可能什么数据也没有接收到,因为发送方发送的数据有可能在传输途中都丢失了。,8.1 UDP协议简介,在Java中,java.util.DatagramSocket负责接收和发送UDP数据报,java.util.DatagramPacket表示UDP数据报。如图8-1所示,每个DatagramSocket与一个本地地址(包括本地主机的IP地址和本地UDP端口)绑定,每
3、个DatagramSocket可以把UDP数据报发送给任意一个远程DatagramSocket,也可以接收来自任意一个远程DatagramSocket的UDP数据报。在UDP数据报中包含了目的地址的信息,DatagramSocket根据该信息把数据报发送到目的地。,8.1 UDP协议简介,UDP协议是无连接的协议,客户端的DatagramSocket与服务器端的DatagramSocket不存在一一对应关系,两者无需建立连接,就能交换数据报。 DatagramSocket提供了接收和发送数据报的方法: public void receive(DatagramPacket dst)throws
4、IOException /接收数据报 public void send(DatagramPacket src)throws IOException /发送数据报,8.1 UDP协议简介,例程8-1的EchoServer与例程8-2的EchoClient就利用DatagramSocket来发送和接收数据报。 同一时刻,可能会有多个EchoClient进程与EchoServer进程通信。EchoServer的DatagramSocket与UDP端口8000绑定,EchoClient则与任意一个可用的UDP端口绑定。EchoServer在一个while循环中不断接收EchoClient的数据报,然后
5、给EchoClient回复一个数据报。 EchoClient从控制台读取用户输入的字符串,把它包装成一个数据报,再把它发送给EchoServer,接着再接收EchoServer的响应数据报。,8.2 DatagramPacket类,DatagramPacket表示数据报,它的构造方法可以分为两类: 一类构造方法创建的DatagramPacket对象用来接收数据 还有一类构造方法创建的DatagramPacket对象用来发送数据。 两类构造方法的主要区别是,用于发送数据的构造方法需要设定数据报到达的目的地址,而用于接收数据的构造方法无需设定地址。,8.2 DatagramPacket类,用于接收
6、数据的构造方法包括: public DatagramPacket(byte data,int length) public DatagramPacket(byte data,int offset, int length) 以上data参数用来存放接收到的数据,参数length指定要接收的字节数,参数offset指定在data中存放数据的起始位置,即dataoffset。如果没有设定参数offset,那么起始位置为data0。,8.2 DatagramPacket类,用于发送数据的构造方法包括: public DatagramPacket(byte data,int offset, int le
7、ngth,InetAddress address,int port) public DatagramPacket(byte data,int offset,int length,SocketAddress address) public DatagramPacket(byte data,int length,InetAddress address,int port) public DatagramPacket(byte data,int length,SocketAddress address) 以上data参数中存放了要发送的数据,参数length指定要发送的字节数,参数offset指定要发
8、送的数据在data中的起始位置,即dataoffset。如果没有设定参数offset,那么起始位置为data0。,8.2 DatagramPacket类,以下两段程序代码都创建了一个数据报,它的送达地址为主机“myhost”的UDP端口100: InetAddress remoteIP=InetAddress.getByName(myhost); int remotePort=100; byte data=hello.getBytes(); /获得字符串“hello”的字符编码 DatagramPacket outputPacket=new DatagramPacket(data,data.l
9、ength, remoteIP,remotePort); 或者: InetAddress remoteIP=InetAddress.getByName(myhost); int remotePort=100; SocketAddress remoteAddr=new InetSocketAddress(remoteIP,remotePort); byte data=hello.getBytes(); DatagramPacket outputPacket=new DatagramPacket(data,data.length, remoteAddr);,8.2.1 选择数据报的大小,Datag
10、ramPacket的构造方法有一个参数length,它决定了要接收或发送的数据报的长度。 对于用于接收数据的DatagramPacket,如果实际接收到的数据报的长度大于DatagramPacket的长度,那么多余的数据就会被丢弃。 因此,必须为DatagramPacket选择合适的长度。 理论上,IPv4数据报的最大长度为65507个字节,如果一个DatagramPacket的长度为65507个字节,那么它就可以接收任何IPv4数据报,而不会丢失数据。 理论上,IPv6数据报的最大长度为65536字节。,8.2.1 选择数据报的大小,选择数据报大小的通用原则是: 如果网络非常不可靠,如分组无
11、线电网络,则要选择较小的数据报,以减少传输中遭破坏的可能性。 如果网络非常可靠,而且传输速度很快,就应当尽可能使用大的数据报。 对于多数网络,8K是一个很好的折衷方案。,8.2.2 读取和设置DatagramPacket的属性,DatagramPacket类包括以下属性: data:表示数据报的数据缓冲区。 offset:表示数据报的数据缓冲区的起始位置。 length:表示数据报的长度。 address:对于用于发送的数据报,address属性表示数据报的目标地址。对于用于接收的数据报,address属性表示发送者的地址。 port:对于用于发送的数据报,address属性表示数据报的目标U
12、DP端口。对于用于接收的数据报,port属性表示接收者的UDP端口。,8.2.2 读取和设置DatagramPacket的属性,DatagramPacket类提供了一系列get方法,用于读取各种属性: public InetAddress getAddress() public int port() public ScoketAddress getSocketAddress() public byte getData() public int getLength() public int getOffset(),8.2.2 读取和设置DatagramPacket的属性,DatagramPack
13、et类提供了一系列set方法,用于设置各种属性: public void setAddress(InetAddress addr) public void setPort(int port) public void setSocketAddress(SocketAddress address) public void setData(byte data) public void setData(byte data, int offset, int length) public void setLength(int length),8.2.3 数据格式的转换,数据报中只能存放字节形式的数据。 在
14、发送方,需要把其他格式的数据转换为字节序列。 在接收方,需要把字节序列转换为原来格式的数据。,8.2.3 数据格式的转换,在发送方,可以利用ByteArrayOutputStream和DataOuputStream来把其他格式的数据转换为字节序列。 例如以下longToByte()方法把long型数组中的数据转换为字节,把它们存放到一个字节数组中,再将其返回: public byte longToByte(long data)throws IOException ByteArrayOutputStream bao=new ByteArrayOutputStream(); DataOutputS
15、tream dos=new DataOutputStream(bao); for(int i=0;idata.length;i+) dos.writeLong(datai); dos.close(); return bao.toByteArray(); ,8.2.3 数据格式的转换,在接收方,可以利用ByteArrayInputStream和DataInputStream来把字节序列转换为原来格式的数据。 例如以下byteToLong()方法把byte数组中的字节转换为long型数据,把它存放到一个long型数组中,再将其返回: public long byteToLong(byte data
16、)throws IOException long result=new longdata.length/8; /一个long数据占8个字节 ByteArrayInputStream bai=new ByteArrayInputStream(data); DataInputStream dis=new DataInputStream(bai); for(int i=0;idata.length/8;i+) resulti=dis.readLong(); return result; ,8.2.4 重用DatagramPacket,同一个DatagramPacket对象可以被重用,用来多次发送或接
17、收数据。 在例程8-3的DatagramTester类中,创建了sender和receiver两个线程。 sender线程负责发送数据,这段操作由send()方法实现。 Receiver线程负责接收数据,这段操作由receive()方法实现。,8.3 DatagramSocket类,DatagramSocket负责接收和发送数据报。 每个DatagramSocket对象都会与一个本地端口绑定,在此端口监听发送过来的数据报。 在客户程序中,一般由操作系统为DatagramSocket分配本地端口,这种端口也称为匿名端口;在服务器程序中,一般由程序显式的为DatagramSocket指定本地端口。
18、,8.3.1 构造DatagramSocket,DatagramSocket的构造方法有以下几种重载形式: (1)DatagramSocket() (2)DatagramSocket(int port) (3)DatagramSocket(int port, InetAddress laddr) (4)DatagramSocket(SocketAddress bindaddr),8.3.1 构造DatagramSocket,如果想知道一个DatagramSocket对象所绑定的本地地址,可以调用它的以下方法: int getLocalPort():返回DatagramSocket所绑定的端口。
19、 InetAddress getLocalAddress():返回DatagramSocket所绑定的IP地址。 SocketAddress getLocalSocketAddress():返回一个SocketAddress对象,它包含DatagramSocket所绑定的IP地址和端口信息。,8.3.2 接收和发送数据报,DatagramSocket的send()方法负责发送一个数据报,该方法的定义如下: public void send(DatagramPacket dp)throws IOException 值得注意的是,UDP协议提供不可靠的传输,如果数据报没有到达目的地,send()方
20、法不会抛出任何异常,因此发送方程序无法知道数据报是否被接收方接收到,除非双方通过应用层的特定协议来确保接收方未收到数据报时,发送方能重发数据报。,8.3.2 接收和发送数据报,DatagramSocket的receive()方法负责接收一个数据报,该方法的定义如下: public void receive(DatagramPacket datagramPacket)throws IOException 此方法从网络上接收一个数据报。如果网络上没有数据报,执行该方法的线程会进入阻塞状态,直到收到数据报为止。,8.3.3 管理连接,两个TCP Socket之间存在固定的连接关系,而一个Datagr
21、amSocket可以与其他任意一个DatagramSocket交换数据报。 在某些场合,一个DatagramSocket可能只希望与固定的另一个远程DatagramSocket通信。例如NFS客户只接收来自与之通信的服务器的数据报,再例如在网络游戏中,一个游戏网家只接收他的游戏搭档的数据报。,8.3.3 管理连接,从JDK1.2开始,DatagramSocket添加了一些方法,利用这些方法,可以使一个DatagramSocket只能与另一个固定的DatagramSocket交换数据报: (1)public void connect(InetAddress host,int port) (2)p
22、ublic void disconnect() (3)public int getPort() (4)public InetAddress getInetAddress() (5)publicSocketAddress getRemoteSocketAddress(),8.3.4 关闭DatagramSocket,DatagramSocket的close()方法会释放所占用的本地UDP端口。 在程序中及时关闭不再需要的DatagramSocket,这是好的编程习惯。,8.3.5 DatagramSocket的选项,DatagramSocket有以下选项: SO_TIMEOUT:表示接收数据报时
23、的等待超时时间。 SO_RCVBUF:表示接收数据的缓冲区的大小。 SO_SNDBUF:表示发送数据的缓冲区的大小。 SO_REUSEADDR:表示是否允许重用DatagramSocket所绑定的本地地址。 SO_BROADCAST:表示是否允许对网络广播地址收发数据报。,8.4 DatagramChannel类,从JDK1.4开始,添加了一个支持按照非阻塞方式发送和接收数据报的DatagramChannel。 DatagramChannel是SelectableChannel的子类,可以注册到一个Selector。 使用DatagramChannel,可以使得UDP服务器只需用单个线程就能同
24、时与多个客户通信。 DatagramChannel默认情况下采用阻塞模式,如果希望该为非阻塞模式,可以调用configureBlocking(false)方法。,8.4.1 创建DatagramChannel,DatagramChannel类的静态open()方法返回一个DatagramChannel对象,每个DatagramChannel对象都关联了一个DatagramSocket对象,DatagramChannel对象的socket()方法返回这个DatagramSocket对象。 DatagramChannel对象创建后,与它关联的DatagramSocket对象还没有绑定到任何地址,必
25、须调用DatagramSocket对象的bind()方法来与一个本地地址绑定: DatagramChannel channel= DatagramChannel.open(); DatagramSocket socket=channel.socket(); SocketAddress address=new InetSocketAddress(8000); socket.bind(address);,8.4.2 管理连接,与DatagramSocket一样,DatagramChannel的connect(SocketAddress remote)方法使得通道只能对特定的远程地址收发数据报。Da
26、tagramChannel的isConnected()方法判断通道是否只能对特定的远程地址收发数据报。 只要调用DatagramChannel的disconnect()方法,就能使得通道能再次对多个远程地址收发数据报。 UDP客户程序通常只和特定的UDP服务器通信,因此可在UDP客户程序中可以把DatagramChannel与远程服务器连接。UDP服务器需要与多个UDP客户程序通信,因此在UDP服务器中一般不用对DatagramChannel进行连接。,8.4.3 用send()方法发送数据报,DatagramChannel的send(ByteBuffer src,SocketAddress
27、target)方法把参数src中的剩余数据作为一个数据报写到通道中,参数target指定目标地址,该方法返回发送的字节数: public int send(ByteBuffer src,SocketAddress target)throws IOException 如果希望把相同数据发给多个客户,可以重用源ByteBuffer。在这种情况下,每次都要把ByteBuffer的位置重新设为零: channel.send(src, target1); src.rewind(); /把缓冲区的位置重设为零 channel.send(src, target2); src.rewind(); /把缓冲区的
28、位置重设为零 channel.send(src, target3);,8.4.4 用receive()方法接收数据报,DatagramChannel的receive(ByteBuffer dst)方法从通道中读取一个数据报,存放在参数指定的ByteBuffer中,并返回数据报的发送方的地址: public SocketAddress receive(ByteBuffer dst)throws IOException 如果DatagramChannel工作于阻塞模式,那么receive()方法在读取到数据报之前不会返回。如果DatagramChannel工作于非阻塞模式,那么receive()方
29、法在没有数据报可读取的情况下立即返回null。,8.4.4 用receive()方法接收数据报,例程8-4的SendChannel和例程8-5的ReceiveChannel分别发送和接收数据报。 SendChannel工作于默认的阻塞模式,每次发送的数据报的长度为1024个字节。ReceiveChannel既可以工作于阻塞模式,也可以工作于非阻塞模式,ReceiveChannel的用来存放接收到的数据报的缓冲区buffer的大小既可以为1024个字节,也可以为4个字节,这都取决于运行ReceiveChannel时设置的命令行参数。,8.4.5 用write()方法发送数据报,write()方法
30、和send()方法一样,也能发送数据报。write()方法有三种重载形式: (1)public int write(ByteBuffer src)throws IOException (2)public long write(ByteBuffer srcs) throws IOException (3)public long write(ByteBuffer srcs, int offset, int length) throws IOException,8.4.5 用write()方法发送数据报,DatagramChannel的write()与send()方法的区别在于: (1)write(
31、)方法要求DatagramChannel已经建立连接,也就是说,程序在调用DatagramChannel的write()方法之前,要求先调用connect()方法使通道与特定的远程接收方连接。而send()方法则没有这一限制。 (2)在非阻塞模式下,write()方法不保证把ByteBuffer内的所有剩余数据作为一个数据报发送。假如ByteBuffer的剩余数据为r,实际发送的字节数为n,那么 0=n=r。而send()方法总是把ByteBuffer内的所有剩余数据作为一个数据报发送。,8.4.6 用read()方法接收数据报,read()方法和receive()方法一样,也能接收数据报。r
32、ead()方法有三种重载形式: public int read(ByteBuffer src)throws IOException public long read(ByteBuffer srcs) throws IOException public long read(ByteBuffer srcs, int offset, int length) throws IOException,8.4.6 用read()方法接收数据报,DatagramChannel的read()与receive()方法的区别在于: read()方法要求DatagramChannel已经建立连接,也就是说,程序在调用
33、DatagramChannel的read()方法之前,要求先调用connect()方法使通道与特定的远程发送方连接。 而receive()方法则没有这一限制。,8.4.6 用read()方法接收数据报,例程8-7的EchoClient使用DatagramChannel与EchoServer通信。 EchoClient类共使用了两个线程:主线程和Receiver线程。主线程主要负责接收和发送数据,这些操作由talk()方法实现。Receiver线程负责读取用户向控制台输入的数据,该操作由receiveFromUser()方法实现。,8.5 组播Socket,网络数据传播按照接收者的数量,可分为以
34、下三种方式: 单播:提供点对点的通信。 广播:发送者每次发送的数据可以被传播范围内的所有接收者接收。 组播:发送者每次发送的数据可以被小组内的所有接收者接收。,8.5 组播Socket,组播组内的所有主机共享同一个地址,这种地址称为组播地址。组播地址是范围在 55之间的IP地址。此范围内的所有地址的前4个二进制位都是“1110”。组播地址也被称为D类IP地址,与其他的A类、B类和C类地址相区别。组播组是开放的,主机可以在任何时候进入或离开组。 IANA(Internet Assigned Numbers Authority)组织负责分发永久组播地址。
35、,8.5 组播Socket,组播与单播UDP的区别在于,前者必须考虑TTL(Time To Live)值,它用IP数据包的头部的一个字节表示。 TTL通过限制IP包被丢弃前通过的路由器数目,来决定IP包的生存时间。IP包每通过一个路由器,TTL就减一,当TTL变为0,这个包就被丢弃。 TTL的一个作用是防止配置有误的路由器把包在路由器之间无限的来回传递,还有一个作用是限制组播的地理范围。,8.5.1 MulticastSocket类,.MulticastSocket具有组播的功能,它是DatagramSocket的子类: public class MulticastSocket extends
36、 DatagramSocket 和DatagramSocket一样,MulticastSocket也与DatagramPacket搭配使用,DatagramPacket用来存放接收和发送的组播数据报。,8.5.1 MulticastSocket类,如果要接收组播数据报,只需创建一个MulticastSocket,把它加入到组播组,就能接收发送到该组的组播数据。 发送组播数据报与发送单播数据报非常相似,只需创建一个MulticastSocket,无需把它加入到组播组(当然也可以把它加入到组播组),就能向一个组播组发送数,8.5.1 MulticastSocket类,1构造MulticastSoc
37、ket MulticastSocket有以下构造方法: (1)public MulticastSocket() throws SocketException (2)public MulticastSocket(int port) throws SocketException (3)public MulticastSocket(SocketAddress bindAddress) throws SocketException,8.5.1 MulticastSocket类,2与组播组通信 MulticastSocket支持以下四种操作: (1)加入到组播组:joinGroup()方法 (2)向组中
38、成员发送数据报:send()方法 (3)接收发送到组播组的数据报:receive()方法 (4)离开组播组:leaveGroup()方法,8.5.1 MulticastSocket类,3设置和获得MulticastSocket的属性 MuliticastSocket类提供了两组用于设置和读取网络接口的方法。MuliticastSocket只会对该网络接口中的组收发组播数据: /第1组方法 public void setInterface(InetAddress address)throws SocketException public InetAddress getInterface()thr
39、ows SocketException /第2组方法 public void setNetworkInterface(NetworkInterface interface)throws SocketException public NetworkInterface getNetworkInterface() throws SocketException,8.5.2 组播Socket的范例,例程8-8的MulticastSender类向一个IP地址为的组播组发送数据报。MulticastSocket发送数据报的方式与DatagramSocket非常相似: DatagramPac
40、ket dp = new DatagramPacket(buffer, buffer.length,group,port); ms.send(dp); /发送组播数据报 MulticastSocket不管是否加入到组播组,都能发送组播数据报。因此把程序中的“ms.joinGroup(group);”这一行注释掉,不会影响程序的运行效果。,8.5.2 组播Socket的范例,在例程8-9的MulticastReceiver类中,MulticastSocket加入到IP地址为的组播组,然后不断接收发往该组的数据报。MulticastSocket接收数据报的方式与DatagramS
41、ocket非常相似: DatagramPacket dp = new DatagramPacket(buffer, buffer.length); ms.receive(dp); /接收组播数据报,练习题1,问题:以下哪些叙述是正确的? 选项: a) DatagramSocket的send(DatagramPacket src)方法发送数据报时,如果无法送达接收方,该方法会抛出IOException。 b) UDP协议是无连接的协议。 c) 对于用于接收数据的DatagramPacket,如果实际接收到的数据报的长度大于DatagramPacket的长度,那么多余的数据就会被丢弃。 d) DatagramSocket的getInputStream()方法用于获得输入流。 答案: b,c,练习题2,问题:以下是DatagramPacket的构造方法,哪些用于发送数据报? 选项: a)public DatagramPacket(byte data,int length) b)public DatagramPacket(byte data,int offset, int length) c)publi
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026年中医基础理论题库(附答案)
- 保险行业职业道德与规范备考习题
- 以工匠精神雕琢时代品质(教学课件)-高中语文
- 插秧歌(教学课件)-高中语文
- 医疗质量评审业务考试题完整版及答案2026年
- 2026年永久基本农田保护专题试题及答案
- 林业局事业单位面试题和专业题15问及答案
- 客运驾驶员安全教育培训考试试题及答案1
- 医院后勤库管主管岗位面试题及答案
- 助理电力调度员题库及答案
- 2025年城管协管员笔试考试试题(含答案)
- 2026河北机关事业单位工人技能等级考试(汽车驾驶员·高级)历年参考题库含答案详解2卷
- 正压送风口阀体损坏更换安装调试方案
- 新学期(2026年秋)小学二年级体育教学工作计划
- 第二届重庆市市场监管系统执法办案电子数据取证技能大竞赛赛完整试题
- 中考物理电路设计与电路故障分析三年2023-2025中考真题分类汇编解析版
- 煤炭销售部管理制度(3篇)
- 中海大海洋工程环境学课件03波浪流体力学理论
- 2025年检验检测机构授权签字人考核试题(含答案)
- 十二指肠营养管
- 跟腱断裂的术后护理
评论
0/150
提交评论