How to send a serialized class over sockets using TCP protocal in Java?

To clarify, this class holds important client information that has to arrive in its entirety without missing or corrupted information. I need to send this class as a variable that holds some client information from a client to a server, and the server stores that variable in an array.

I could send it using ObjectOutputStream but is it safe to use this to send client information? If the client information arrives makes or breaks my project. (I can only use java in my project)

I tried searching across the internet for a relateable solution but none was sufficient enough.

My knowledge specifically in how to explain the Java language in English is limited since I didn’t learn this language using English, so I hope you understand my question.

EDIT: Added the class.

public class ClientInformation implements Serializable 
{
    /**
     * 
     */
    private static final long serialVersionUID = -8904366211043587433L;
    private int arrplace;
    private int mode;
    private int ip;
    private String myusername;
    private String username;
    private int password;
    private Dimension screenResolution;
    public ClientInformation (int ip, String myusername, String username, int password,Dimension screenResolution, int mode, int arrplace) {
        this.ip = ip;
        this.myusername = myusername;
        this.username = username;
        this.password = password;
        this.screenResolution = screenResolution;
        this.mode = mode;
    }
    public int getarrplace()
    {
        return arrplace;
    }
    public int getmode()
    {
        return mode;
    }
    public int getip()
    {
        return ip;
    }
    public String getmyusername()
    {
        return myusername;
    }
    public String getusername()
    {
        return username;
    }
    public int getpass()
    {
        return password;
    }
    public Dimension getscreenRes()
    {
        return screenResolution;
    }
    public void setarrplace(int arrplace)
    {
        this.arrplace = arrplace;
    }
    public void setmode (int mode)
    {
        this.mode = mode;
    }
    public void setmyusername (String myusername)
    {
        this.myusername = myusername;
    }
    public void setusername (String username)
    {
        this.username = username;
    }
    public void setpass(int password)
    {
        this.password = password;
    }
    public void setscreenRes(Dimension screenResolution)
    {
        this.screenResolution = screenResolution;
    }
}

Answer

Here you go. I made an entire implementation for you, which writes its data directly on the stream. I would recommand using eigher an SSL Socket or an encrypted stream (CipherInput- and CipherOutputStream). To write this class to a stream just call writeTo on it and pass in an Outputstream or to read in pass an InputStream to its constructor.

Note: DON’T forget to close (and flush) the streams after calling the corresponding methods. I didn’t make them close inside the writeTo method and the constructor, because you might still need the streams to read or write more data.

Here you go (I tested it. It is fully functional and will even write and read null values correctly):

public static final class ClientInformation implements Serializable {
    private static final long serialVersionUID = -8904366211043587433L;
    
    private static final Charset CHARSET = StandardCharsets.UTF_8;

    private int arrplace;
    private int mode;
    private int ip;
    private String myusername;
    private String username;
    private final int password;
    private Dimension screenResolution;

    public ClientInformation(int ip,
                             String myusername,
                             String username,
                             int password,
                             Dimension screenResolution,
                             int mode,
                             int arrplace) {
        this.ip = ip;
        this.myusername = myusername;
        this.username = username;
        this.password = password;
        this.screenResolution = screenResolution;
        this.mode = mode;
        this.arrplace = arrplace;
    }

    public ClientInformation(InputStream in) throws IOException {
        int l;
        byte[] sb = null, ib = new byte[4];

        // Read arrplace
        readFully(in, ib, 0, 4);
        arrplace = getInt(ib, 0);

        // Read mode
        readFully(in, ib, 0, 4);
        mode = getInt(ib, 0);

        // Read ip
        readFully(in, ib, 0, 4);
        ip = getInt(ib, 0);

        // Read myusername
        readFully(in, ib, 0, 4);
        l = getInt(ib, 0);
        sb = resize(sb, l);
        if (l >= 0) {
            readFully(in, sb, 0, l);
            myusername = new String(sb, 0, l, CHARSET);
        } else {
            myusername = null;
        }

        // Read username
        readFully(in, ib, 0, 4);
        l = getInt(ib, 0);
        sb = resize(sb, l);
        if (l >= 0) {
            readFully(in, sb, 0, l);
            username = new String(sb, 0, l, CHARSET);
        } else {
            username = null;
        }

        // Read password
        readFully(in, ib, 0, 4);
        password = getInt(ib, 0);

        // Read screenWidth
        readFully(in, ib, 0, 4);
        int screenWidth = getInt(ib, 0);

        // Read screenHeight
        readFully(in, ib, 0, 4);
        int screenHeight = getInt(ib, 0);

        screenResolution = new Dimension(
                screenWidth,
                screenHeight
        );
    }

    public void writeTo(OutputStream os) throws IOException {
        String s;
        int l;
        byte[] sb, ib = new byte[4];

        // Write arrplace
        putInt(ib, 0, arrplace);
        os.write(ib, 0, 4);

        // Write mode
        putInt(ib, 0, mode);
        os.write(ib, 0, 4);

        // Write ip
        putInt(ib, 0, ip);
        os.write(ib, 0, 4);

        // Write myusername
        s = myusername;
        if (s != null) {
            sb = s.getBytes(CHARSET);
            putInt(ib, 0, l = sb.length);
            os.write(ib, 0, 4);
            os.write(sb, 0, l);
        } else {
            putInt(ib, 0, -1);
            os.write(ib, 0, 4);
        }

        // Write username
        s = username;
        if (s != null) {
            sb = s.getBytes(CHARSET);
            putInt(ib, 0, l = sb.length);
            os.write(ib, 0, 4);
            os.write(sb, 0, l);
        } else {
            putInt(ib, 0, -1);
            os.write(ib, 0, 4);
        }

        // Write password
        putInt(ib, 0, password);
        os.write(ib, 0, 4);

        Dimension screenRes = screenResolution;

        // Write screenRes.getWidth()
        putInt(ib, 0, (int) screenRes.getWidth()); // Get width actually returns an integer
        os.write(ib, 0, 4);

        // Write screenRes.getHeight()
        putInt(ib, 0, (int) screenRes.getHeight()); // Get height actually returns an integer
        os.write(ib, 0, 4);
    }

    static byte[] resize(byte[] b, int newLen) {
        if (newLen < 0) return b;
        if (b == null || b.length < newLen) {
            return new byte[newLen];
        } else return b;
    }

    static void putInt(byte[] b, int off, int val) {
        b[off + 3] = (byte) (val);
        b[off + 2] = (byte) (val >>> 8);
        b[off + 1] = (byte) (val >>> 16);
        b[off] = (byte) (val >>> 24);
    }

    static int getInt(byte[] b, int off) {
        return ((b[off + 3] & 0xFF)) +
                ((b[off + 2] & 0xFF) << 8) +
                ((b[off + 1] & 0xFF) << 16) +
                ((b[off]) << 24);
    }

    static void readFully(InputStream in, byte[] b, int off, int len) throws IOException {
        int n = 0;
        while (n < len) {
            int count = in.read(b, off + n, len - n);
            if (count < 0) {
                throw new EOFException();
            }
            n += count;
        }
    }

    // Don't forget to add all the getters and setter you had
}

Here is the sample code I used to test this class:

try {
    // Serialize
    ClientInformation info = new ClientInformation(
            30,
            "MyUsername",
            "My Real Username",
            3485,
            new Dimension(300, 200),
            19,
            20
    );

    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    info.writeTo(bos);
    bos.flush();

    // Deserialize
    ByteArrayInputStream in = new ByteArrayInputStream(bos.toByteArray());
    ClientInformation receivedInfo = new ClientInformation(in);

    System.out.println(receivedInfo.ip);
    System.out.println(receivedInfo.myusername);
    System.out.println(receivedInfo.username);
    System.out.println(receivedInfo.password);
    System.out.println(receivedInfo.screenResolution);
    System.out.println(receivedInfo.mode);
    System.out.println(receivedInfo.arrplace);
} catch (Throwable tr) {
    tr.printStackTrace();
}

Leave a Reply

Your email address will not be published. Required fields are marked *