【问题标题】:Truncate DatagramPacket byte array截断 DatagramPacket 字节数组
【发布时间】:2014-09-02 09:35:50
【问题描述】:

我正在与DatagramPackets 和DatagramSockets 合作来制作客户端/服务器情况。我有一个带有简单客户端和服务器的工作项目。客户端会向服务器发送一个序列化的对象,就是这样。

下面显示的代码完美运行。我将发布整个类,以防万一有人想运行代码。

我想要做的是将发送的数据截断为刚好适合的数组(基于How to get rid of the empty remaining of the buffer?)。

当我打印出我发送的长度和收到的长度时,我确实得到了这个输出:

GameClient: sent 330 bytes to the server
GameServer: received 330 bytes

我在接收端首先做的是:

        socket.receive(packet);
        // Deserialize the object.
        TestObject received = TestObject.deserialize(packet.getData());

但是,我已将缓冲区大小设置为任意大小,因此我认为我应该将实际字节放入适合对象的字节数组中。所以我尝试了以下方法:

        socket.receive(packet);
        // Truncate the data into a smaller byte array.
        int actualSize = packet.getLength();
        byte[] actualPacket = new byte[actualSize];
        System.arraycopy(packet.getData(), packet.getOffset(), data, 0, packet.getLength());

        // Deserialize the object.
        TestObject received = TestObject.deserialize(actualPacket); // Does not work.

但是,这段代码给了我期望

java.io.StreamCorruptedException: invalid stream header: 00000000

在第一行TestObjectdeserialize方法中抛出:

        ObjectInputStream iStream = new ObjectInputStream(
                new ByteArrayInputStream(data));

这可能是什么问题?数据是精确的副本,对吧?

对象发送

package net;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class TestObject implements Serializable
{
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    public int value;
    public double anotherValue;
    public byte[] fillMe;

    public TestObject(int value)
    {
        super();
        this.value = value;
        fillMe = new byte[123];
    }

    public TestObject(int value, double anotherValue)
    {
        super();
        this.value = value;
        this.anotherValue = anotherValue;
    }

    public static byte[] serialize(TestObject o)
    {
        try
        {
            ByteArrayOutputStream baos = new ByteArrayOutputStream(2048);
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(o);
            oos.close();
            // get the byte array of the object
            byte[] obj = baos.toByteArray();
            baos.close();
            return obj;
        } catch (Exception e)
        {
            e.printStackTrace();
        }

        return null;
    }

    public static TestObject deserialize(byte[] data)
    {
        try
        {
            ObjectInputStream iStream = new ObjectInputStream(
                    new ByteArrayInputStream(data));
            TestObject obj = (TestObject) iStream.readObject();
            iStream.close();
            return obj;
        } catch (Exception e)
        {
            e.printStackTrace();
        }

        return null;
    }
}

服务器(接收端)

package net;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

import utils.Printer;
import engine.board.GameBoard;

public class GameServer extends Thread
{   private static int BUFFER_SIZE = 64000; //64k buffer
    private static final int SERVER_LISTENING_PORT = 1234;
    private DatagramSocket socket;
    private GameBoard game;

    public GameServer(GameBoard game)
    {
        this.game = game;
        try
        {
            this.socket = new DatagramSocket(SERVER_LISTENING_PORT);
        } catch (SocketException e)
        {
            e.printStackTrace();
        }
    }

    public void run()
    {
        while(true)
        {
            byte[] data = new byte[BUFFER_SIZE];
            DatagramPacket packet = new DatagramPacket(data,  data.length);
            try
            {
                socket.receive(packet);
                Printer.debugMessage(this.getClass(), String.format("received %s bytes", packet.getLength()));
            } catch (IOException e)
            {
                e.printStackTrace();
            }
            // Truncate the data into a smaller byte array.
            int actualSize = packet.getLength();
            byte[] actualPacket = new byte[actualSize];
            System.arraycopy(packet.getData(), packet.getOffset(), data, 0, packet.getLength());

            // Deserialize the object.
            TestObject received = TestObject.deserialize(actualPacket); // Does not work.
            //TestObject received = TestObject.deserialize(packet.getData()); // Works fine?
            System.out.println("Server received object with value " + received.value);
        }
    }
}

客户(发送端)

package net;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;

import utils.Printer;
import engine.board.GameBoard;

public class GameClient
{
    private static int BUFFER_SIZE = 64000;
    private static final int SERVER_LISTENING_PORT = 1234;
    private InetAddress serverIp;
    private DatagramSocket socket;
    private GameBoard game;
    private String clientName;

    public GameClient(String name, GameBoard game, String ipAddress)
    {
        this.game = game;
        this.clientName = name;
        try
        {
            this.socket = new DatagramSocket();
            this.serverIp = InetAddress.getByName(ipAddress);
        } catch (SocketException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (UnknownHostException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }


    public void sendData(byte[] data)
    {
        DatagramPacket packet = new DatagramPacket(data, data.length, serverIp, SERVER_LISTENING_PORT);

        try
        {
            socket.send(packet);
            Printer.debugMessage(this.getClass(), String.format("sent %d bytes to the server", data.length));;

        } catch (IOException e)
        {
            e.printStackTrace();
        }
    }
}

测试代码

import net.GameClient;
import net.GameServer;
import net.TestObject;


public class Scratchpad
{
    static GameServer server;
    static GameClient client;
    static GameClient client2;
    public static void main(String[] args)
    {
        // Start the server
        server = new GameServer(null);
        server.start();

        // Init client (sender).
        client = new GameClient("client1", null, "localhost");

        // Create object to send.
        TestObject tester = new TestObject(1234);

        // Send the object.
        client.sendData(TestObject.serialize(tester));
        //client2.sendData("hello world".getBytes());
    }
}

【问题讨论】:

    标签: java sockets


    【解决方案1】:

    你不需要这些。您可以从原始 byte[] 数组中反序列化。它将在对象的末尾停止。最后的任何尾随内容都将被忽略。

    但是,您可以大大简化您的新代码:

        TestObject received = TestObject.deserialize(packet.getData(), packet.getOffset(), packet.getLength());
    

    并将您的反序列化方法更改为:

    public static TestObject deserialize(byte[] data, int offset, int length)
    {
        try
        {
            ObjectInputStream iStream = new ObjectInputStream(
                    new ByteArrayInputStream(data, offset, length));
            // etc ...
    }
    

    我会进一步修改它以允许它抛出异常而不是默默地吞下它们。返回null 是一个特别糟糕的策略,因为null 是一个带内值,可能是您尝试传输的值。

    【讨论】:

    • 哦,太好了:)谢谢!我很清楚这些例外情况,但我正在尝试通过实验来让某些东西发挥作用。既然我理解了,我将使代码更加健壮! :) 谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-10-07
    • 1970-01-01
    • 2014-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多