【问题标题】:How can I append packets in Java?如何在 Java 中附加数据包?
【发布时间】:2019-10-11 18:32:30
【问题描述】:

我有一个使用Netty 构建的简单客户端/服务器系统,我使用数据包发送数据。 在我的例子中,Packet 有两种方法可以从BytBuf 写入和读取。 例如,包含字符串的数据包从字符串中获取字节并将它们写入ByteBuf,然后将其发送,或者它从ByteBuf 中读取字节并创建消息。 这是我的数据包接口中的代码 sn-p:

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

解码也一样,反之亦然。

我希望它变得清楚。

【问题讨论】:

  • 这个范围很广。你能提供更多细节吗?你能举例说明你到目前为止所做的事情吗?请参考How to ask a good questioncreate a Minimal, Complete, Verifiable example
  • 这个问题对我来说没有多大意义。什么是数据包?什么是消息?将数据包附加到消息意味着是什么意思?这与 netty ByteBuf 有什么关系?据我所知,这个类是一个通用的“字节序列的持有者”,它没有附加事物的概念。或消息。或数据包。
  • 现在更糟了。您现在已经添加了自定义类具有字节的概念。和包裹。您的术语非常混乱。我有一种感觉,你脑子里有一个相当模糊的概念设计。不幸的是,您需要用清晰准确的术语来描述它(最好使用定义明确的术语)。而且我怀疑这要么太难了,要么会让你的问题的文本......页面很长......
  • 你知道netty和发送数据包的概念吗?
  • 你的意思是DatagramPacket?是的,我熟悉数据报。但是数据报没有附加任何东西。 ByteBuf 不是 DatagramPacket。现在您正在谈论附加到数据包的数据包。真的很混乱,

标签: java server netty packet


【解决方案1】:

我不会创建 Packet 类。如果您想发送整个对象,我只会使用BufferedOutputStream 手动发送数据或ObjectOutputStream。您还可以通知遥控器您发送的内容(在附加数据之前发送字符串或其他任何内容)。

例如

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;
    }
}

【讨论】:

  • 我明白你的意思。但我不确定 Netty 是否支持发送 Streams,据我所知,您必须将所有数据转换为字节并将其添加到 ByteBuf
  • 使用 DataInputStream 和 DataOutputStream。
【解决方案2】:

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

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 相同。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-10-19
    • 2021-12-20
    • 2021-02-01
    • 1970-01-01
    • 2018-05-25
    • 1970-01-01
    • 1970-01-01
    • 2021-07-07
    相关资源
    最近更新 更多