我正在使用DatagramPacket
和DatagramSocket
来制作客户端/服务器情况。我有一个简单的客户端和服务器的工作项目。客户端会将一个序列化的对象发送到服务器并且就是它。
下面显示的代码完美无缺。我将发布整个类,以防任何人想要运行代码。
我尝试做的是将发送的数据截断为恰好适合的数组(基于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
在第一行的deserialize
TestObject
方法中抛出:
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;
}
}
SERVER(接收端)
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();
}
}
}
TESTCODE
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());
}
}
答案 0 :(得分: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
是一个带内值,可能是您尝试传输的值。