注意:所有文章除特别说明外,转载请注明出处.
UDP
[TOC]
基于UDP协议的Socket编程
1. 基于UDP协议的Socket网络编程步骤
1.利用 DatagramPacket 对象封装数据报
DatagramPacket类将数据字节填充到UDP数据包中,是数据报
2.利用 DatagramSocket 对象发送数据报
DatagramSocket类收发数据报。
3.利用 DatagramSocket 对象接收数据报
4.利用 DatagramPacket 对象处理数据报
提示:DatagramPacket类,封装了数据报的数据、数据长度、目标地址和目标端口。DatagramSocket类,接收和发送DatagramPacket对象封装好的数据报。
提示:UDP的这种职责划分与TCP使用的Socket与ServerSocket不一样。1. UDP没有两台主机间唯一连接的概念。一个Socket会收发所有指向指定端口的数据,不需要知道对方是哪一个远程主机。一个 DatagramSocket 可以从多个独立主机收发数据。与TCP不一样的是,UDP的Socket不专用与一个连接。
2. 基于UDP协议的Socket通信
这一过程可以类比与快递礼物的收发过程,礼物-数据,包裹-DatagramPacket,快递点-DatagramSocket,寄礼物-send(),收礼物-receive()。
2.1 基于UDP协议的Socket通信(服务端)
package cn.edu.xidian.see.*.Inet.UDPSocket;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketAddress;
import java.net.SocketException;
public class LogicServicer {
public static void main(String[] args) {
byte[] infos = new byte[1024];
DatagramPacket dp = new DatagramPacket(infos,infos.length);
//快递点
DatagramSocket socket=null;
try {
socket = new DatagramSocket(5000);
//在快递点取礼物
socket.receive(dp);
//拆礼物
String info = new String(dp.getData(),0,dp.getData().length);
System.out.println("客户端说:"+info);
//给客户端一个响应
String reply ="一件羽绒服";
byte[] reply2 = reply.getBytes();
//客户端地址
SocketAddress sa = dp.getSocketAddress();
//打开一个包裹
DatagramPacket dp1 = new DatagramPacket(reply2,reply2.length,sa);
//寄出去
socket.send(dp1);
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
socket.close();
}
}
}
2.2 基于UDP协议的Socket通信(客户端)
package cn.edu.xidian.see.*.Inet.UDPSocket;
import java.io.IOException;
import java.net.*;
public class LogicClient {
public static void main(String[] args) {
//买礼物
String info="心形巧克力!";
byte[] infos = info.getBytes();
//对方地址和邮编(端口号)
InetAddress ia;
//快递点
DatagramSocket socket = null;
try {
//localhost = 127.0.0.1 回环地址
ia = InetAddress.getByName("localhost");
//包裹包装礼物
DatagramPacket dp = new DatagramPacket(infos, infos.length, ia, 5000);
socket = new DatagramSocket();
//通过快递点往外寄出礼物
try {
socket.send(dp);
} catch (IOException e) {
e.printStackTrace();
}
//接收服务器的响应
byte[] replys = new byte[1024];
DatagramPacket dp1 = new DatagramPacket(replys,replys.length);
socket.receive(dp1);
String reply = new String(dp1.getData(),0,dp.getData().length);
System.out.println("服务器的响应:"+reply);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
socket.close();
}
}
}
DatagramPacket 类
DatagramSocket 类
DatagramChannel
DatagramChannel类用与非阻塞UDP应用程序,与SocketChannel和ServerSocketChannel用于非阻塞TCP应用程序一样。类似于SocketChannel和ServerSocketChannel,DatagramChannel是SelectableChannel的子类,可以注册到一个Selector。
在UDP中,一个数据报Socket可以处理多个客户端的输入和输出请求。而DatagramChannel类所增加的就是能够以非阻塞的方式做到这一点。这样的话如果网络没有立即准备好收发数据,这些方法可以迅速返回。
1. 打开socket
//1. 创建通道
DatagramChannel channel = DatagramChannel.open();
//2. 监听通道的地址
SocketAddress address = new InetSocketAddress(3122);
//3. 监听连接
DatagramSocket socket = channel.socket();
//4. 绑定端口
socket.bind(address);
2. 接收
receive()方法从通道读取一个数据报包,放在一个ByteBuffer中。返回这个包的主机地址。
public SocketAddress receive(ByteBuffer dst) throws IOException;
如果通道是阻塞的话,上面方法在读取到包之前不会返回。如果通道是非阻塞的话,没有包可以在读取的情况下该方法立即返回null。
3. 发送
send()方法将一个数据报从ByteBuffer写入通道,要写到第二个参数指定的地址。
public int send(ByteBuffer src, SocketAddress target) throws IOException;
注意:如果希望向多个客户端发送相同的数据,可以重用源ByteBuffer。不过在之前需要将其回倒(rewind/flip())。
4. 连接
我们在打开一个数据通道之后,能够通过connect()方法将它连接到一个特定的远程地址。
SocketAddress address = new InetSocketAddress();
channel.connect(address);
5. 读取
6. 写入
选择TCP通道与选择数据报通道之间有一个主要区别。因为数据报通道实际上是无连接的(尽管有connect()方法),所以需要注意传输何时结束何时关闭。
7. 关闭
在结束操作时关闭通道,释放其占用的端口和其它资源。