0

I am receiving an EOFException when the receiver of a UDP packet attempts to read it. Instances that are charged with reading and decoding UDP packets are called Engager objects. They contain a socket which is created in the Engager's constructor, and a method called getEngagementPacketSize is where the packet is received and read. Both methods are quoted together here:

public Engager(){
    MulticastSocket s=null;
    try{
        s=new MulticastSocket(6789);
        s.joinGroup(InetAddress.getByName("224.0.0.1"));
    }catch(IOException ex){
        ex.printStackTrace(System.out);
    }
    this.socket=s;
}

private int getEngagementPacketSize()throws Exception{
    byte[]bytes=new byte[Integer.BYTES]; 
    DatagramPacket dp=new DatagramPacket(bytes,Integer.BYTES);
    this.socket.receive(dp);

    ByteArrayInputStream bais=new ByteArrayInputStream(bytes);
    ObjectInputStream ois=new ObjectInputStream(bais);
    int eps=ois.readInt();
    ois.close();

    return eps;
}

The exception occurs on the call to ois.readInt().

On the sender, the packet is created and sent thus:

    InetAddress ia=null;
    try{
        ia=InetAddress.getByName("224.0.0.1");
    }catch(UnknownHostException ex){
        NewInstance_CannotConstructMulticastDestination x=new NewInstance_CannotConstructMulticastDestination(ac);
        x.initCause(ex);
        throw x;
    }

    MulticastSocket ms=null;
    try{
        ms=new MulticastSocket(6789);
        ms.joinGroup(ia);
    }catch(IOException ex){
        NewInstance_CannotConstructMulticastSocket x=new NewInstance_CannotConstructMulticastSocket(ac);
        x.initCause(ex);
        throw x;
    }

    NamedSovereignAlias nsa=new NamedSovereignAlias("Self");
    Engagement engagement=new Engagement(nsa,nsa,ac.getName(),ac.getPresynapticDelegate());

    byte[]engagementBytes=null;
    ByteArrayOutputStream baosEngagement=new ByteArrayOutputStream();
    try(ObjectOutputStream oos=new ObjectOutputStream(baosEngagement)){
        oos.writeObject(engagement);
        oos.close();
    }catch(Exception ex){
        NewInstance_CannotCreateBodyContent x=new NewInstance_CannotCreateBodyContent(ac);
        x.initCause(ex);
        throw x;
    }
    engagementBytes=baosEngagement.toByteArray();

    byte[]epsBytes=null;
    ByteArrayOutputStream baosEps=new ByteArrayOutputStream();
    try(ObjectOutputStream oos=new ObjectOutputStream(baosEps)){
        oos.writeInt(engagementBytes.length);
        oos.close();
    }catch(Exception ex){
        NewInstance_CannotCreateHeadContent x=new NewInstance_CannotCreateHeadContent(ac);
        x.initCause(ex);
        throw x;
    }
    epsBytes=baosEps.toByteArray();

    System.out.println("Length of header ["+epsBytes.length+"].");

    try{
        DatagramPacket dp=new DatagramPacket(epsBytes,epsBytes.length,ia,6789);
        ms.send(dp);
    }catch(Exception ex){
        NewInstance_CannotSendHeadPacket x=new NewInstance_CannotSendHeadPacket(ac);
        x.initCause(ex);
        throw x;
    }

I am asking this question because I receive an EOFException on the receiver when I try to read the first of two UDP packets. Hence, my code showing how the second packet is packaged and sent is not disclosed (it is actually commented out, so there is no reason to suspect that the second packet is being received first). The first packet contains just an integer that represents the number of bytes in the second packet. The second packet (if it were sent) contains a single instance of an Engagement. I haven't quoted the Engagement class here because it's length (not its form) matters. The sender informs me that the first packet should be 10 bytes in length; that is what one observes in the system output window when the System.println statement is executed in the listing above just before the packet is sent.

Why isn't the receiver able to read the integer from the packet? Is the problem in the sender or the receiver? Could it be both?

Help greatly received. Thanks,

Owen.

1 Answers1

1

Is the problem in the sender or the receiver? Could it be both?

The problem is on the receiving end. You are allocating the packet buffer like this:

byte[] bytes = new byte[Integer.BYTES]; 

That is too small. If you look at the Object Serialization Specification, you will see that an a serialization stream starts with a 2 byte "magic number" and a 2 byte protocol version number. So by my calculations, the buffer needs to be at least 8 bytes ... and possibly more.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • Hmmm... possibly more... that might explain why I am being told by the sender that the length of the header packet (the one that contains the length of the packet that is to follow) is 10 bytes. Thanks for the tip, I'll look into it and get back. –  Apr 23 '16 at 06:47
  • @OwenThomas You should use a datagram of the largest expected size, not the smallest you can think of. Largest expected size plus one, actually, so you can detect protocol errors. I would suggest something in the region of 1500 bytes. – user207421 Apr 23 '16 at 07:01
  • @EJP Thanks for the tip. What I'm trying to do could best be likened to the sender being a light source, and the cluster of receivers being a retina. I know UDP is inherently unreliable. However, as I'll be multicasting to possibly a very large number of devices at once, I envisage that some few of them will get the message and engage the sender correctly. A receiver that doesn't receive a message that it can work with will simply ignore it. –  Apr 23 '16 at 07:11
  • @OwenThomas I meant for receiving. You should send what you need to send and no more. – user207421 Apr 23 '16 at 07:13
  • According to the grammar disclosed in the spec, I have defined constants in my Engager class for the size of the magic, version, blockdata, and the blockdata size fields. I'd appreciate it very much if someone could point to API import of these definitions if one exists. –  Apr 23 '16 at 12:22