1

我试图通过首先序列化它然后在另一端反序列化它来通过 udp 发送和反对。我认为这将是微不足道的,因为我之前通过 udp 发送了其他数据并将内容序列化到文件等。

我现在已经调试了一段时间,并且在接收端不断收到 EOFException。数据包正确到达,但不知何故反序列化失败。我不确定错误是发件人还是收件人。我想问题可能与接收方不知道数据包的大小有关。

这是我的发件人类:

    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 中获取数据包大小。虽然无法让它工作。

4

2 回答 2

2

据我所知,接收函数返回它接收到的字节的长度。但是您的缓冲区将已满:

例子:

int buffersize = 1024;

您通过 udp 发送 8 个字节。

因此byte[],您的 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;
}
于 2013-07-30T07:13:43.000 回答
1

在 UDP 上接收数据时,始终使用java.net.DatagramSocket.getReceiveBufferSize();. 这是平台的实际大小或套接字的 SP_RCVBUF。由于 UDP 是一种基于数据报的协议,而 TCP 是流式协议,因此接收缓冲区对于数据完整性至关重要。通常,接收和发送缓冲区的大小是相等的,但是使用时发送时您不会受到打扰DatagramSocket.send(DatagramPacket),或者,您也可以使用 DatagramSocket.setSendBufferSize(DatagramSocket.getSendBufferSize())用于使用SO_SNDBUF此套接字的选项。请记住,在 UDP 中,如果您使用的 SO_SNDBUF 大小大于平台大小,则可以丢弃数据包。

于 2013-10-03T15:43:30.183 回答