netty實現udp編程比普通的java原生api實現udp編程要稍微複雜一些,但是一旦實現了,也很簡單,而且我們不用關心socket這部分,我們只需要關注我們的業務代碼即可。
這裏給出一個模擬udp server與client的示例,看代碼部分,兩者很像,但是也有區別,server主要偏向bind並且監聽端口,等待客戶端連接。而client偏向向server發送數據並接收返回的數據。
無論是server,還是client,他們的主要收發數據邏輯會在各自handler中體現。
udp客戶端,不像tcp客戶端那樣,需要明確指定建立socket連接,即非必須存在connect這一步,只是在發送的packet中指定發送的目的host與port,這也符合udp協議的特點,是一種非可靠的傳輸協議。
UDPServerApp.java
package com.xxx.udpnetty;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;
public class UDPServerApp {
public static void main(String[] args) {
Bootstrap bootstrap = new Bootstrap();
EventLoopGroup workGroup = new NioEventLoopGroup();
bootstrap.group(workGroup).channel(NioDatagramChannel.class)
.option(ChannelOption.SO_BROADCAST, true)
.handler(new ChannelInitializer<NioDatagramChannel>() {
@Override
protected void initChannel(NioDatagramChannel ch) throws Exception {
// TODO Auto-generated method stub
ch.pipeline().addLast(new UDPServerHandler());
}
});
try {
Channel channel = bootstrap.bind("192.168.0.107", 8080).sync().channel();
channel.closeFuture().sync().await();
} catch (Exception e) {
e.printStackTrace();
}
}
}
UDPServerHandler.java
package com.xxx.udpnetty;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.DatagramPacket;
public class UDPServerHandler extends SimpleChannelInboundHandler<DatagramPacket>{
@Override
protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg)
throws Exception {
ByteBuf buf = msg.content();
int len = buf.readableBytes();
byte[] data = new byte[len];
buf.readBytes(data);
String receive = new String(data,"UTF-8");
System.out.println(receive);
ctx.writeAndFlush(new DatagramPacket(Unpooled.wrappedBuffer("hello,netty".getBytes()), msg.sender()));
}
}
UDPClientApp.java
package com.xxx.udpnetty;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;
public class UDPClientApp {
public static void main(String[] args) {
Bootstrap bootstrap = new Bootstrap();
EventLoopGroup workGroup = new NioEventLoopGroup();
bootstrap.group(workGroup).channel(NioDatagramChannel.class)
.option(ChannelOption.SO_BROADCAST, true)
.handler(new ChannelInitializer<NioDatagramChannel>() {
@Override
protected void initChannel(NioDatagramChannel ch) throws Exception {
// TODO Auto-generated method stub
ch.pipeline().addLast(new UDPClientHandler());
}
});
try {
Channel channel = bootstrap.bind(0).sync().channel();
channel.closeFuture().sync().await();
} catch (Exception e) {
e.printStackTrace();
}
}
}
UDPClientHandler.java
package com.xxx.udpnetty;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.DatagramPacket;
public class UDPClientHandler extends SimpleChannelInboundHandler<DatagramPacket>{
@Override
protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg)
throws Exception {
ByteBuf buf = msg.content();
int len = buf.readableBytes();
byte[] data = new byte[len];
buf.readBytes(data);
String receive = new String(data,"UTF-8");
System.out.println("client->"+receive);
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer("hello,server",Charset.forName("UTF-8")),
new InetSocketAddress("192.168.0.107", 8080)));
}
}
這裏我們需要先啓動UDPServerApp.java,然後啓動UDPClientApp.java
這時候,控制檯會分別打印hello,server 、 client->hello,netty。
無論是java原生api實現的udp,還是netty實現的udp,都是需要有一個server監聽一個端口,等待連接;客戶端啓動通過發送一個請求send(datagrampacket)建立連接,而不是類似tcp那樣connect(host,port)來建立連接,服務端會根據收到的請求來發送一個回覆給客戶端,因爲這時候服務端才知道客戶端連接的ip和端口,才能通過ip和端口給客戶端發送回覆,否則,服務端不知道要向誰發送回覆數據。
我們仔細觀察會發現UDPServerApp.java和UDPClientApp.java代碼幾乎一模一樣,不同的只有兩句,分別是設置handler,和bind這裏。
1 、 ch.pipeline().addLast(new UDPServerHandler());
ch.pipeline().addLast(new UDPClientHandler());
2 、 Channel channel = bootstrap.bind("192.168.0.107", 8080).sync().channel(); //bind是爲了監聽
Channel channel = bootstrap.bind(0).sync().channel(); //bind是爲了建立datagramsocket,這個端口可以隨便定義,只要不與8080重複即可。
這裏不管是server,還是client發送數據,都是datagrampacket,而且都需要指定host,port,只有這樣才能發送給目標,否則就是沒有目的的發送,不會被程序所接收。