Witam.
Chciałem przetestować przesyłanie obiektów za pomocą Netty 4.1.36 używając UDP.
Znalazłem prosty przykład (klient-serwer) przesyłający tekst.
Serwer
package nettyserverudp;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.nio.NioDatagramChannel;
public class NettyServerUDP {
public NettyServerUDP() {
try {
Bootstrap b = new Bootstrap();
EventLoopGroup group = new NioEventLoopGroup();
Bootstrap handler = b.group(group).channel(NioDatagramChannel.class).option(ChannelOption.SO_BROADCAST, true).handler(new UdpServerHandler());
b.bind(9292).sync().channel().closeFuture().await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public class UdpServerHandler extends SimpleChannelInboundHandler<DatagramPacket> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception {
ByteBuf buf = packet.copy().content();
byte[] req = new byte[buf.readableBytes()];
buf.readBytes(req);
String body = new String(req, "UTF-8");
System.out.println(body);
while(true) {
String json = "Z serwera";
byte[] bytes = json.getBytes("UTF-8");
DatagramPacket data = new DatagramPacket(Unpooled.copiedBuffer(bytes), packet.sender());
ctx.writeAndFlush(data);
}
}
}
public static void main(String[] args) {
new NettyServerUDP();
}
}
Klient
package nettyclientudp;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.util.CharsetUtil;
import java.net.InetSocketAddress;
public class NettyClientUDP {
public static final int MessageReceived = 0x99;
private static int scanPort = 9292;
public NettyClientUDP() {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group).channel(NioDatagramChannel.class).handler(new CLientHandler());
Channel ch = b.bind(0).sync().channel();
ch.writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer("Z klienta", CharsetUtil.UTF_8),new InetSocketAddress("localhost", scanPort))).sync();
ch.closeFuture().await();
} catch (Exception e) {
e.printStackTrace();
} finally {
group.shutdownGracefully();
}
}
private class CLientHandler extends SimpleChannelInboundHandler<DatagramPacket> {
int i = 0;
@Override
protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception {
String body = packet.content().toString(CharsetUtil.UTF_8);
System.out.println("["+i+"] "+body);
i++;
}
}
public static void main(String[] args) {
new NettyClientUDP();
}
}
Działa ładnie. Chciałbym jednak aby przesyłał całe obiekty. Zmodyfikowałem kod i otrzymuję błedy.
Klasa-obiekt
package nettyserverudp;
import java.io.Serializable;
public class Message implements Serializable {
public String name = "";
public int old = 0;
public Message(String name, int old) {
this.name = name;
this.old = old;
}
}
Serwer
package nettyserverudp;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.nio.NioDatagramChannel;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class NettyServerUDP {
public NettyServerUDP() {
try {
Bootstrap b = new Bootstrap();
EventLoopGroup group = new NioEventLoopGroup();
Bootstrap handler = b.group(group).channel(NioDatagramChannel.class).option(ChannelOption.SO_BROADCAST, true).handler(new UdpServerHandler());
b.bind(9292).sync().channel().closeFuture().await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public class UdpServerHandler extends SimpleChannelInboundHandler<DatagramPacket> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception {
ByteBuf buf = packet.copy().content();
byte[] req = new byte[buf.readableBytes()];
buf.readBytes(req);
Message mess = deserialize(req);
System.out.println(mess.toString());
}
}
public byte[] serialize(Message mess) {
byte[] stream = null;
try (
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
) {
oos.writeObject(mess);
stream = baos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return stream;
}
public Message deserialize(byte[] stream) {
Message mess = null;
try (ByteArrayInputStream bais = new ByteArrayInputStream(stream);
ObjectInputStream ois = new ObjectInputStream(bais);) {
} catch (IOException e) {
e.printStackTrace();
}
return mess;
}
public static void main(String[] args) {
new NettyServerUDP();
}
}
Klient
package nettyclientudp;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.util.CharsetUtil;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetSocketAddress;
public class NettyClientUDP {
public static final int MessageReceived = 0x99;
private static int scanPort = 9292;
public NettyClientUDP() {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group).channel(NioDatagramChannel.class).handler(new CLientHandler());
Channel ch = b.bind(0).sync().channel();
Message mess = new Message("jan",34);
byte[] bytes = this.serialize(mess);
Message ret = this.deserialize(bytes);
System.out.println("ret mess "+ret.name);
ch.writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer(bytes),new InetSocketAddress("localhost", scanPort))).sync();
ch.closeFuture().await();
} catch (Exception e) {
e.printStackTrace();
} finally {
group.shutdownGracefully();
}
}
private class CLientHandler extends SimpleChannelInboundHandler<DatagramPacket> {
int i = 0;
@Override
protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception {
String body = packet.content().toString(CharsetUtil.UTF_8);
System.out.println("["+i+"] "+body);
i++;
}
}
public byte[] serialize(Message mess) {
byte[] stream = null;
try (
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
) {
oos.writeObject(mess);
stream = baos.toByteArray();
} catch (IOException e) {
// Error in serialization
e.printStackTrace();
}
return stream;
}
public Message deserialize(byte[] stream) {
Message mess = null;
try (ByteArrayInputStream bais = new ByteArrayInputStream(stream);
ObjectInputStream ois = new ObjectInputStream(bais);) {
mess = (Message) ois.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return mess;
}
public static void main(String[] args) {
new NettyClientUDP();
}
}
Klient po uruchomieniu przesyła dane.
1-serializuje obiekt do tablicy bajtów.
2-podczas tworzenia DatagramPacket zostaje utworzony ByteBuf na podstawie tablicy bajtów i przesłany.
Serwer odbiera pakiet.
1-odczytuje ByteBuf
2-uzupełnia tablicę bajtów.
3-tworzy na jej podstawie obiekt.
Niestety podczas deserializacji otrzymuję błąd
run:
java.lang.ClassNotFoundException: nettyclientudp.Message
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:338)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:682)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1859)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1745)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2033)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1567)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:427)
at nettyserverudp.NettyServerUDP.deserialize(NettyServerUDP.java:67)
at nettyserverudp.NettyServerUDP$UdpServerHandler.channelRead0(NettyServerUDP.java:41)
at nettyserverudp.NettyServerUDP$UdpServerHandler.channelRead0(NettyServerUDP.java:33)
at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:105)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1408)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:930)
at io.netty.channel.nio.AbstractNioMessageChannel$NioMessageUnsafe.read(AbstractNioMessageChannel.java:93)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:682)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:617)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:534)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:496)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:906)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:748)
cze 05, 2019 3:06:35 PM io.netty.channel.DefaultChannelPipeline onUnhandledInboundException
WARNING: An exceptionCaught() event was fired, and it reached at the tail of the pipeline. It usually means the last handler in the pipeline did not handle the exception.
java.lang.NullPointerException
at nettyserverudp.NettyServerUDP$UdpServerHandler.channelRead0(NettyServerUDP.java:42)
at nettyserverudp.NettyServerUDP$UdpServerHandler.channelRead0(NettyServerUDP.java:33)
at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:105)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1408)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:930)
at io.netty.channel.nio.AbstractNioMessageChannel$NioMessageUnsafe.read(AbstractNioMessageChannel.java:93)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:682)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:617)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:534)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:496)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:906)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:748)
Tablica bajtów którą tworzy klient i otrzymuje serwer są zgodne. Zawierają tę samą długość i zawartość.
Dodam jeszcze że serializacja i deserializacja w obrębie jednego programu odbywa się prawidłowo.
Klasa Message zawarte w programie klienta i serwera są identyczne;
Co robię źle?