Java中通过udp发送对象
我试图通过udp发送和对象,首先序列化它,然后在另一端反序列化它。我认为这将是微不足道的,因为我以前通过udp发送过其他数据,并将数据序列化到文件中 我已经调试了一段时间了,我一直在接收端收到EOFEException。数据包正确到达,但反序列化失败。我不确定错误是在发送方还是接收方。我想问题可能是接收者不知道数据包的大小 这是我的发件人类:Java中通过udp发送对象,java,serialization,udp,deserialization,eofexception,Java,Serialization,Udp,Deserialization,Eofexception,我试图通过udp发送和对象,首先序列化它,然后在另一端反序列化它。我认为这将是微不足道的,因为我以前通过udp发送过其他数据,并将数据序列化到文件中 我已经调试了一段时间了,我一直在接收端收到EOFEException。数据包正确到达,但反序列化失败。我不确定错误是在发送方还是接收方。我想问题可能是接收者不知道数据包的大小 这是我的发件人类: package com.machinedata.sensordata; import java.io.ByteArrayOutputStream
package com.machinedata.sensordata;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import android.content.Context;
import android.util.Log;
import com.machinedata.io.DataSerializer;
import com.machinedata.io.ManagerUdpPacket;
/**
* This class sends udp-packets. It is used to send driver's information to the manager tablet.
* @author tuomas
*
*/
public class UdpSender
{
private final int MANAGER_PORT = 1234;
private String ip = "192.168.11.50"; //tablet's IP
private DatagramSocket sock = null;
private InetAddress host;
private String mType;
private DataSerializer dataser;
public UdpSender(Context context)
{
try
{
sock = new DatagramSocket();
host = InetAddress.getByName(ip); //tabletin ip
}
catch(Exception e)
{
System.err.println("Exception alustettaessa senderia" + e);
}
dataser = new DataSerializer(context);
}
/**
* With this function we can send packets about our machine to the manager to
* see in the fleet-view.
*/
public void sendToManager(ManagerUdpPacket managerUdp)
{
//serialize
Log.v("sendudp", "Send a packet: " + managerUdp.getDriver());
//serialize
byte[] data = dataser.serializeManagerPacket(managerUdp);
//send
try
{
DatagramPacket dp = new DatagramPacket(data , data.length , host , MANAGER_PORT);
sock.send(dp);
}
catch(IOException e)
{
System.err.println("IOException senderissa " + e);
}
}
public void close()
{
sock.close();
}
}
以下是序列化函数:
/**
* Serializes packet to be sent over udp to the manager tablet.
*/
public byte[] serializeManagerPacket(ManagerUdpPacket mp)
{
try
{
ByteArrayOutputStream baos = new ByteArrayOutputStream(2048);
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(mp);
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 class UdpReceiver {
private DatagramSocket clientSocket;
private byte[] receiveData;
private final int timeout = 1;
/**
* Create a receiver.
* @param port Port to receive from.
* @param signCount Number of signals in a packet
*/
public UdpReceiver(int port)
{
//receiveData = serializeManagerPacket(new ManagerUdpPacket("asd", new MachineData(1, 2, "asd", "modelName"), 1,2,3,4,5.0,null));
try{
clientSocket=new DatagramSocket(port);
clientSocket.setReceiveBufferSize(2048);
clientSocket.setSoTimeout(timeout);
}catch(SocketException e){
Log.e("ERR", "SocketException in UdpReceiver()");
}
}
public void close()
{
clientSocket.close();
}
/**
* Receive a data packet and split it into array.
* @param data Array to put data in, must be correct size
* @return True on successful read, false otherwise
*/
public ManagerUdpPacket receive()
{
//receive a packet
DatagramPacket recvPacket = new DatagramPacket(receiveData, receiveData.length);
try{
clientSocket.receive(recvPacket);
}catch(IOException e){
Log.e("ERR", "IOException in UdpReceiver.receive");
return null;
}
ManagerUdpPacket obj = deserializeManagerPacket(receiveData);
if (obj != null)
Log.v("udpPacket", "UDP saatu: " + obj.getDriver());
return obj;
}
/**
* Deserialize the udp-packet back to readable data.
* @param data
* @return
*/
public ManagerUdpPacket deserializeManagerPacket(byte[] data)
{
try
{
ObjectInputStream iStream = new ObjectInputStream(new ByteArrayInputStream(data));
ManagerUdpPacket obj = (ManagerUdpPacket) iStream.readObject();
iStream.close();
return obj;
}
catch(Exception e)
{
e.printStackTrace();
}
return null;
}
}
在接收端侦听数据包的线程:
dataStreamTask = new TimerTask()
{
public void run()
{
if (currentlyStreaming)
{
ManagerUdpPacket mp = udpReceiver.receive();
if(mp != null)
{
Log.v("log", "Paketti saatu! " + mp.getDriver());
}
//stop thread until next query
try {
synchronized(this){
this.wait(queryInterval);
}
} catch (InterruptedException e) {
Log.e("ERR", "InterruptedException in TimerTask.run");
}
}
}
最后是我通过UDP发送的类:
public class ManagerUdpPacket implements Serializable
{
private static final long serialVersionUID = 9169314425496496555L;
private Location gpsLocation;
private double totalFuelConsumption;
private long operationTime;
//workload distribution
private long idleTime = 0;
private long normalTime = 0;
private long fullTime = 0;
private int currentTaskId;
private String driverName;
String machineModelName = "";
String machineName = "";
int machineIconId = -1;
int machinePort = -1;
public ManagerUdpPacket(String driver, MachineData machine, int currentTaskId, long idleTime, long fullTime, long operationTime, double fuelConsumption, Location location)
{
driverName = driver;
this.currentTaskId = currentTaskId;
this.idleTime = idleTime;
this.fullTime = fullTime;
this.operationTime = operationTime;
this.totalFuelConsumption = fuelConsumption;
this.gpsLocation = location;
machineModelName = machine.getModelName();
machineName = machine.getName();
machineIconId = machine.getIconId();
machinePort = machine.getPort();
}
public String getDriver()
{
return driverName;
}
public int getCurrentTaskId()
{
return currentTaskId;
}
public long getIdleTime()
{
return idleTime;
}
public long getFullTime()
{
return fullTime;
}
public long getOperationTime()
{
return operationTime;
}
public double getTotalFuelConsumption()
{
return totalFuelConsumption;
}
public double getLocation()
{
return gpsLocation.getLatitude();
}
public String getMachineModelName()
{
return machineModelName;
}
public String getMachineName()
{
return machineName;
}
public int getMachineIconId()
{
return machineIconId;
}
public int getMachinePort()
{
return machinePort;
}
}
我试图从序列化数据包的大小或插入任意2048数据包的大小中获取数据包的大小,基于internet上的一些示例。但无法使其工作。据我所知,receive函数返回它接收的字节长度。但您的缓冲区将满: 例如:
int buffersize=1024代码>
通过udp发送8字节
因此,您的字节[]
将充满8个字节,但1024个字节中的其余部分将为0
保存通过.receive()调用获得的大小,只需将缓冲区的所有值保存到另一个字节[],就可以得到对象
例如:
public ManagerUdpPacket receive()
{
int receivedBytes = 0;
//receive a packet
DatagramPacket recvPacket = new DatagramPacket(receiveData, receiveData.length);
try{
receivedBytes = clientSocket.receive(recvPacket);
}catch(IOException e){
Log.e("ERR", "IOException in UdpReceiver.receive");
return null;
}
byte[] myObject = new byte[receivedBytes];
for(int i = 0; i < receivedBytes; i++)
{
myObject[i] = receiveData[i];
}
ManagerUdpPacket obj = deserializeManagerPacket(myObject);
if (obj != null)
Log.v("udpPacket", "UDP saatu: " + obj.getDriver());
return obj;
}
公共管理器rudpacket receive()
{
int receivedBytes=0;
//收到一个包
DatagramPacket recvPacket=新的DatagramPacket(receiveData,receiveData.length);
试一试{
receivedBytes=clientSocket.receive(recvPacket);
}捕获(IOE异常){
Log.e(“ERR”,“udpreciver.receive中的IOException”);
返回null;
}
byte[]myObject=新字节[receivedBytes];
for(int i=0;i
在UDP上接收数据时,始终使用java.net.DatagramSocket.getReceiveBufferSize()代码>。这是插座的平台或SP_RCVBUF的实际尺寸。由于UDP是一种基于数据报的协议,与TCP不同,TCP是一种流协议,因此接收缓冲区对于数据健全性至关重要。通常,接收缓冲区和发送缓冲区的大小相等,但在使用DatagramSocket.send(datagramspacket)
发送时,您不会感到麻烦,或者,您也可以使用DatagramSocket.setSendBufferSize(DatagramSocket.getSendBufferSize())
来使用此套接字的SO\SNDBUF
选项。请记住,在UDP中,如果使用的sou SNDBUF大小大于平台的大小,则数据包可能会被丢弃 将接收到的数据写入receiveData字节数组。因此,这将充满您收到的数据。但由于它是2048字节大,其余的都是0。如果尝试反序列化此字节数组,它将尝试读取整个2048字节。你必须拆下阵列。因此,您需要创建一个新的字节数组,其大小与接收到的数据相同(通过读取接收到的数据量即可知道)。现在可以反序列化此字节数组。感谢您的解释和示例代码!现在开始工作:)顺便说一句,clientSocket.receive()是一个无效函数,所以我必须使用clientSocket.receive(recvPacket);receivedBytes=recvPacket.getLength();相反以防万一其他人读到了答案,然后想知道。哦,是的。。。对此xD感到抱歉。您的反序列化失败,因为您正在尝试反序列化字节流的一部分。您应该仅在接收到整个数据后调用反序列化。