Java socket data works only when sending time is delayed

1k Views Asked by At

I am sending a protobuf from C++ to Java via a raw socket, the C++ program being the client and the java program being the server. The C++ program generates packets almost every 1ms which is sent to the java program.

If I run the program normally, I see that there are only the half the packets being received.

If I set a breakpoint in the C++ program and then run the client and the server, all the packets are received.

How do I ensure that all packets are received without setting a breakpoint? Can I introduce a delay?

All the packets have bytes sizes upto a maximum of 15 bytes.

3

There are 3 best solutions below

10
On

By default TCP sockets use the "Nagle Algorithm" which will delay transmission of the next "unfilled" fragment in order to reduce congestion. Your packet size is small enough and the time delay between packets is small enough that the nagle algorithm will have an effect on your transmissions.

1
On

As already discussed in the comments, what you are trying to do won't work in a reliable way. This is also described in the Protobuf documentation:

If you want to write multiple messages to a single file or stream, it is up to you to keep track of where one message ends and the next begins. The Protocol Buffer wire format is not self-delimiting, so protocol buffer parsers cannot determine where a message ends on their own. The easiest way to solve this problem is to write the size of each message before you write the message itself. When you read the messages back in, you read the size, then read the bytes into a separate buffer, then parse from that buffer. (If you want to avoid copying bytes to a separate buffer, check out the CodedInputStream class (in both C++ and Java) which can be told to limit reads to a certain number of bytes.)

The bold italic part is where you code isn't correct.

On the write side you should write

  1. the Protobuf's length in some format that is understandable for both sender and receiver (selecting the proper format is especially important when transporting between systems whose endianness is different).
  2. the protobuf

On the receiving end you need to

  1. perform a read with the fixed, known size of the length field
  2. a read for the length learned in step 1. This read will retriev the protobuf.

There's example code here on SO in this question: Sending struct via Socket using JAVA and C++

0
On

@fvu: This is my code which I am trying:

import Visualization.DataSetProtos.PacketData; // protos import

import java.io.InputStream;
import java.util.Arrays;
import javax.swing.JFrame;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;


class WorkerThread extends Thread {
Socket service;
static DynamicData demo;
static int size;
static int times;
static byte[] buffer;

WorkerThread(Socket service) 
{
    this.service = service;
    buffer = new byte[500];
    size = 1;
    times = 0;
}

static void Print(PacketData packetData) 
{
    System.out.print("Packet Number: " + (++times));
    System.out.print("  DataSet Size: " + packetData.getLength() + "\n");

}

static void Print(PacketHeader packetHeader) 
{
    System.out.print("Packet Number: " + (++times));
    System.out.print("  DataSet Size: " + packetHeader.getLength() + "\n");

}

public void run() {
boolean flag=true;    //you can change this flag's condition, to test if the client disconects

    if(demo == null)
    {
        demo = new DynamicData("GridMate Data Visualization");
        demo.pack();
        RefineryUtilities.centerFrameOnScreen(demo);
        //demo.setVisible(true);
    }
try
{
    while (flag)
    {

        InputStream inputStream = service.getInputStream();
        int read;
        read = inputStream.read(buffer);

        byte[] readBuffer = new byte[read];
        readBuffer = Arrays.copyOfRange(buffer, 0, read);
        PacketData packetData = PacketData.parseFrom(readBuffer);
        Print(packetData);


    }
    service.close();
}
catch(Exception e)
    {
        e.printStackTrace();
    }
}
}



public class Test
{
Test()
{
   server = null;
   client= null;
}
public static void main(final String[] args) {
    int i =0;
    try 
    {
        server = new ServerSocket(25715);

    System.out.println("Server setup and waiting for client connection ...");

            while(true)
            {
                client = server.accept();
                WorkerThread wt = new WorkerThread(client);
                wt.start();
                i++; 
           }
    }
  catch(IOException e)
  { System.out.println("IO Error in streams " + e);
    e.printStackTrace();
  }

}
 public void finalize()
 {
    try
    {
        server.close();
        client.close();
    }
    catch(Exception e)
    {
       e.printStackTrace();
    }

   }

    static ServerSocket server;
    static Socket client;
}