Netty 4 UDP przesyłanie obiektów - serializacja

0

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?

0

Powinieneś korzystać z tej samej klasy z tego samego pakietu.
nettyclientudp.Message i nettyserverudp.Message pomimo takiej samej zawartości to różne klasy.

0

Fakt. Nie ma błędów ale obiekt nie zawiera również żadnej zawartości.

0

Przepraszam bardzo. Działa. Wielkie dzięki. Siedziałem nad tym 3 dni i nie dałem rady. A tu o taką malutką rzecz chodziło.
Jeszcze raz Wielkie dzięki. Zaoszczędziłeś mi mnóstwo czasu i nerwów. Pozdrawiam

1 użytkowników online, w tym zalogowanych: 0, gości: 1