实现一个UDP应用关键的点:
1、和tcp的不同,udp没有接收的说法,所以即使是接收端,也使用Bootstrap
2、指定channel为NioDatagramChannel
3、发送的时候发送数据包,并需要指定发送的ip和端口号
实战:发送一个消息hello,返回world
接收端
UDPReceiver
public class UDPReceiver {
private int port;
private EventLoopGroup group;
private Bootstrap b;
public UDPReceiver(int port) {
this.port = port;
group = new NioEventLoopGroup();
//和tcp的不同,udp没有接受的说法,所以即使是接收端,也使用Bootstrap
b = new Bootstrap();
b.group(group)
//由于我们用的是UDP协议,所以要用NioDatagramChannel来创建
.channel(NioDatagramChannel.class)
//向ChannelPipeline里添加业务处理handler
.handler(new UDPReceiveHandler());
}
/**
* 启动
* @throws InterruptedException
*/
public void start() throws InterruptedException {
try {
//没有接受客户端连接的过程,监听本地端口即可
b.bind(this.port).sync();
System.out.println("服务器启动成功");
} finally {
}
}
/**
* 资源优雅释放
*/
public void close() {
try {
if (group != null)
group.shutdownGracefully().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException, IOException {
UDPReceiver udpReceiver = new UDPReceiver(9999);
try {
udpReceiver.start();
//防止主程序退出
System.in.read();
} finally {
udpReceiver.close();
}
}
}
UDPReceiveHandler
public class UDPReceiveHandler extends SimpleChannelInboundHandler<DatagramPacket> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception {
//获得请求
String req = packet.content().toString(CharsetUtil.UTF_8);
System.out.println("UDPReceiveHandler:" + req);
if (req.equals("hello")){
/**
* 重新 new一个DatagramPacket对象,我们通过packet.sender()
* 来获取发送者的地址。
* 重新发送出去!
*/
ctx.writeAndFlush(
new DatagramPacket(
Unpooled.copiedBuffer("world", CharsetUtil.UTF_8),
packet.sender()));
}
}
}
发送端
public class UDPSender {
private Channel channel;
private EventLoopGroup group;
private Bootstrap b;
public UDPSender() {
//第一个线程组是用于接收Client连接的
group = new NioEventLoopGroup();
//服务端辅助启动类
b = new Bootstrap();
b.group(group)
//由于我们用的是UDP协议,所以要用NioDatagramChannel来创建
.channel(NioDatagramChannel.class)
//向ChannelPipeline里添加业务处理handler
.handler(new UDPSenderHandler());
try {
//不需要建立连接
channel = b.bind(0).sync().channel();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 发送消息
* @param msg
* @return
*/
public boolean send(String ip,int port,String msg) throws InterruptedException {
//将UDP请求的报文以DatagramPacket打包发送给接受端
channel.writeAndFlush(new DatagramPacket(
Unpooled.copiedBuffer("hello",CharsetUtil.UTF_8),
new InetSocketAddress(ip,port)
)).sync();//同步调用
return true;
}
/**
* 关闭释放资源
*/
public void close(){
try {
if (group != null)
group.shutdownGracefully().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
UDPSender udpSender = new UDPSender();
udpSender.send("127.0.0.1",9999,"hello");//单播
// udpSender.send("255.255.255.255",9999,"hello");//广播
}
}
如果是广播,把ip改成255.255.255.255,发送到这个地址的消息都将会被定向给本地网络(0.0.0.0)上的所有主机,而不会被路由器
转发给其他的网络。
public class UDPSenderHandler extends SimpleChannelInboundHandler<DatagramPacket> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception {
//获得请求
String req = packet.content().toString(CharsetUtil.UTF_8);
System.out.println(req);
}
}
运行接收端,运行客户端