Question

I want to send an array of point (Point points[] = new point[20]) with DataOutputStream over a socket and be able to correctly read it with DataInputStream on the other side. I CANNOT send each element separately, it must be sent as a whole array and be able to be interpreted as a whole array.

Was it helpful?

Solution

See e.g. the section "Transporting Custom Objects" in Advanced Socket Programming:

  1. Put your data into a Serializable class, say MyData. (You don't really have to do this in your case, because arrays implement Serializable, but there is a chance that later you will want to send other data along with your point array...)
  2. On the sender side, create a MyData object and fill it with data. Cast socket.getOutputStream() to an ObjectOutputStream, and call its writeObject method to send the MyData object.
  3. On the receiver side, cast socket.getInputStream() to an ObjectInputStream, and call its readObject method to receive the object (you will have to cast it to MyData).

Anyway, I would also consider using RMI. For example, you could create a PointServer, register it in the RMI registry, and access it through simple function calls in your client application. RMI is much easier to work with than sockets. For example, you don't have to design a protocol, you only need to define methods for your distributed objects.

OTHER TIPS

Why not use an ObjectInputStream/ObjectOutputStream instead?

Here's a piece of code for something I wrote long ago, it will allow you to send any kind of object through the wire so long as it's serializable, obviously:

ObjectInputStream input = new ObjectInputStream(communicationSocket.getInputStream());
if (input != null) {
   try {
    Object o = input.readObject();
       if (o != null && o instanceof DataObject) {
      DataObject response = (DataObject) o;
           {
               //Do something cool with DataObject
           }
   }
}//etc...

DataObject is just a "wrapper"/custom class that you can define as having as one of it's properties a Point[]; in other words, you could define DataObject as:

import java.io.Serializable;

public class DataObject implements Serializable {

   private Point[] points; //etc - define getter setter for points
}

And you can write it as:

output = new ObjectOutputStream(communicationSocket
                    .getOutputStream());
output.writeObject(yourDataObject);

Now, you can read this as so:

while (listening) {  
    try {
   Object currentObject = input.readObject();
   if (currentObject != null
    && currentObject instanceof DataObject) {
       Point[] points = ((DataObject) currentObject).getPoints();
           //Do something with points
   }
} 
    catch (IOException e) {
   e.printStackTrace();
} 
    catch (ClassNotFoundException e) {
   e.printStackTrace();
} 
    finally {
   listening = false;
}
}

Well, there are some points that you should be aware of, for example, the size of an int 32 or 64 bits, the byte order of the sending and the receiving machines, etc. Also, there should be a protocol to communicate both sockets, I mean, there should be a header in every packets send so that you know how much data you are going to received, I won't deal with that, I assume that you want to send and receive an array of 20 points. In this example it's assumed that both machines are 32 bits, i.e. an int is 4 bytes in size and that both machines use LITTLE_ENDIAN byte order.

// To send an array of points use these two methods:    
public byte[] pointsToBytes(Point[] p, int numPts)
{
  // 2 is for x and y and 4 is the size of an int in bytes
  ByteBuffer buff = ByteBuffer.allocateDirect(numPts * 2 * 4);
  buff.order(ByteOrder.LITTLE_ENDIAN);
  for (int i = 0; i < numPts; i++)
  {
     buff.putInt(p[i].x);
     buff.putInt(p[i].y);
  }
  return buff.array();
}

public boolean sendData(Point[] pts, int size)
{
  try
  {
      byte[] buffer = pointsToBytes(pts, size);
      mainSocket.getOutputStream().write(buffer, 0, buffer.length);
      return true;
  }
  catch (Exception e)
  {
     e.printStackTrace();
  }
  return false;
}

// To receive an array of point use these two methods:

public Point[] bytesToPoints(byte[] byteBuff, int numBytes)  
{
   ByteBuffer buff = ByteBuffer.wrap(byteBuff);
   buff.order(ByteOrder.LITTLE_ENDIAN);
   // 2 is for x and y and 4 is the size of an int in bytes
   int ptsInBuffer = numBytes / 2 / 4;
   Point[] pts = new Point[ptsInBuffer];
   for (int i = 0; i < ptsInBuffer; i++)
   {
       pts[i].x=buff.getInt();
       pts[i].y=buff.getInt();
   }
   return pts;
 }

 public Point[] getData(int pointsToRead)
 {
    try
    {
        byte[] buffer = new byte[pointsToRead * 4 * 2]; 
        int bytesRead = mainSocket.getInputStream().read(buffer, 0, pointsToRead*4*2);
        return bytesToPoints(buffer, bytesRead);
    }
    catch (Exception e)
    {
       e.printStackTrace();
    }
    return null;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top