如何在Java中附加数据包?

时间:2019-05-25 12:21:36

标签: java server netty packet

我有一个使用Netty构建的简单客户端/服务器系统,并且我使用数据包发送数据。 在我的情况下,Packet有两种写入BytBuf的方法。 例如,包含字符串的数据包从字符串中获取字节,并将其写入ByteBuf,然后将其发送,或者从ByteBuf中读取字节并创建消息。 这是我的数据包界面中的代码段:

import io.netty.buffer.ByteBuf;

public abstract class Packet {

    public abstract void read(ByteBuf byteBuf);

    public abstract void write(ByteBuf byteBuf);
}

首先,当接收到数据包时,我想检查是否有数据包连接,然后再访问或读取它。

问题在于接收到数据包时的实例化。我可以将第二个数据包追加到另一个数据包中,并将其存储在第一个数据包的本地变量中,但是当我使用Class.newInstance()在服务器端重新创建该数据包时,它就消失了。

据我所知,Netty的ByteBuf无法读取或编写自己的类...

我唯一的想法是发送多个包裹,我可以避免吗?

编辑

我使用的分组系统的定义。

由于没有很好解释的分组系统,我很快告诉它做什么:

在我的情况下,一个小包包裹着ByteBuf。在Netty中,发送数据的唯一方法是将其以字节形式写在ByteBuf上。基于字符串的数据包的示例为:

package com.sxf.protocol.chat.util.packets;

import io.netty.buffer.ByteBuf;

public class MessagePacket extends Packet {

    private String msg;

    public MessagePacket() {}

    public MessagePacket(String message) {
        this.msg = message;
    }

    @Override
    public void read(ByteBuf byteBuf) {
        byte[] msgBytes = new byte[byteBuf.readInt()];
        byteBuf.readBytes(msgBytes);

        msg = new String(msgBytes);
    }

    @Override
    public void write(ByteBuf byteBuf) {
        byte[] msgBytes = msg.getBytes();

        byteBuf.writeInt(msgBytes.length);
        byteBuf.writeBytes(msgBytes);
    }

    public String getMsg() {
        return msg;
    }
}

创建Packet时,必须以String的形式添加消息。在编码过程中,我调用write()并传递通过管道发送的ByteBuf。然后,将消息形成为字节并写入ByteBuf

解码时也是如此,反之亦然。

我希望事情会变得清楚

2 个答案:

答案 0 :(得分:0)

我不会创建Packet类。我只用BufferedOutputStream手动发送数据,如果要发送整个对象,则使用ObjectOutputStream。您还可以将发送的内容告知远程设备(在附加数据之前发送String或其他任何内容)。

例如

package com.stackoverflow.q56304773;

import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.PrintWriter;

public class PacketSender {
    private OutputStream networkStream;
    public void sendObject(Object o,String objInfo) throws IOException {
        try(BufferedOutputStream out=new BufferedOutputStream(getNetworkStream());
                ObjectOutputStream objectSender=new ObjectOutputStream(out);
                PrintWriter infoWriter=new PrintWriter(out)){
            infoWriter.printf("Object:%s", objInfo);
            objectSender.writeObject(o);
        }
    }
    public OutputStream getNetworkStream() {
        return networkStream;
    }
    public void setNetworkStream(OutputStream networkStream) {
        this.networkStream = networkStream;
    }
}


package com.stackoverflow.q56304773;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;

public class PacketResciever {
    private InputStream networkStream;
    public void resv() throws IOException, ClassNotFoundException {
        try(BufferedInputStream in=new BufferedInputStream(getNetworkStream());
                BufferedReader infoReader=new BufferedReader(new InputStreamReader(in))){
            String header=infoReader.readLine();
            String[] splitted=header.split(":");
            switch(splitted[0]) {
                case "Object":
                    handleObject(new ObjectInputStream(in).readObject(),splitted[1]);
                    break;
                //other cases
            }

        }
    }
    private void handleObject(Object readObject,String info) {
        //search for handler and execute it
    }
    public InputStream getNetworkStream() {
        return networkStream;
    }
    public void setNetworkStream(InputStream networkStream) {
        this.networkStream = networkStream;
    }
}

答案 1 :(得分:0)

我发现一种简单的方法是将一个数据包附加到另一个数据包上,方法是在类中添加一个变量和一些方法,如下所示:

package com.sxf.protocol.chat.util.packets;

import io.netty.buffer.ByteBuf;

public abstract class Packet {

    private Packet attached;

    public abstract void read(ByteBuf byteBuf);

    public abstract void write(ByteBuf byteBuf);

    public final boolean isLinked() {
        return attached != null;
    }

    public final void append(Packet packet) {
        attached = packet;
    }

    public final Packet getAttached() {
        if (isLinked()) {
            return attached;
        }

        throw new NullPointerException("unsafe access to getAttached");
    }
}

使用append(),您可以添加数据包并存储传递的数据包。 isLinked()返回是否附加了数据包。 getAttached()返回附加的数据包。

在编码器中,您检查是否添加了数据包,如果是,则只需调用添加的数据包的编码方法即可。像这样:

    if (packet.isLinked()) {
            out.writeBoolean(true);
            encode(ctx, packet.getAttached(), out);
    } else {
            out.writeBoolean(false);
    }

与解码器和您的自定义ChannelInboundHandler相同。