-2

I am trying to build a simple connection between my Java server (it sends information) and my C client (it receives info).

I want to send one single integer representing the size of an array and then a byte array itself. My java code looks like this

Socket sc = new Socket("52.187.54.73", 19000);

while(true)
{

System.out.println("Socket open");
DataOutputStream outToClient = new DataOutputStream(sc.getOutputStream());

Random rand = new Random(); 
int rlen = rand.nextInt(10)%10 + 1;

 byte[] a = new byte[rlen];
 System.out.println("Size of the array is " + rlen);    


 for(int i = 0; i < rlen; i++)
     a[i] = (byte)rand.nextInt(100);


outToClient.write(rlen);

outToClient.write(a,0,rlen);
//close socket
sc.close(); 
System.out.println("Done!");
//Break once done
break;
}

and my C code looks like this

 ptr1 = (void *)calloc(1, sizeof(int));
 while(1){ 
      sin_size = sizeof(client_addr);
      connected = accept(sock, (struct sockaddr *)&client_addr,&sin_size);
      printf("\n Got a connection from (%s ,%d)",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));

   bytes_received = recv(connected,ptr1,10,0);
   if(bytes_received<0){   
  printf("Something went wrong %s\n", strerror(errno));
   } 

   printf("Bytes received: %d \n", bytes_received);
   for(int i =0; i<bytes_received; i++){

    unsigned char a = *(unsigned char *)(ptr1 + i*sizeof(unsigned char));
    printf("Inc: %d", a);

   }

Assuming that the above block of code works and I am able to get the value of rlen the code for processing the array is as follows:

   ptr2 = calloc(rlen, sizeof(unsigned char)); 
   bytes_received = recv(connected, ptr2, 1,0);// incoming, 0);

   printf("bytes received: %d\n", bytes_received);

   for(int i = 0; i < rlen; i++){ 
       printf(" i = %d, val = %d\n ", i,*(unsigned char *)(ptr2 + i*sizeof(unsigned char)));
    }

Now the Java server sends a number between 1 and 10. I was earlier trying to read the number sent using int incoming = *(int *)ptr1; but for some reason, occasionally I would get huge values like 51020210.

To check why this was happening and debug I wrote the code block:

for(int i =0; i<bytes_received; i++){

    unsigned char a = *(unsigned char *)(ptr1 + i*sizeof(unsigned char));
    printf("Inc: %d", a);

   }

It turns out that sometimes, the integer being sent becomes very large. Why is this happening? On the server side printing out rlen shows me the right value, but non-deterministically I get random really large values at the client side.

Note that whatever number I receive on the client side has the first number as the value of rlen.

So for example if rlen is 6, then the random really large value is something like 689932423

Later the values of rlen will become very large in the order of 1000s so I need to solve this problem and cannot simply take the first byte of whatever I get on the client side.

Sood
  • 149
  • 1
  • 1
  • 11
  • `sizeof(unsigned char)` is always 1. – LPs Sep 13 '16 at 08:28
  • 1
    Java's [`DataOutputStream.write(int)`](https://docs.oracle.com/javase/7/docs/api/java/io/DataOutputStream.html#write(int)) writes a **single byte** to the underlying output stream. You then proceed to read 10 bytes to the buffer pointed to by *ptr1* (which you have not defined in your minimal, complete and verifiable example), after which you cast the pointer to a pointer to int and dereference it. This (probably) breaks aliasing – undefined behaviour – and tries to read too many bytes from your buffer, not to mention possible endianness issues. – Ilja Everilä Sep 13 '16 at 08:29
  • Please indent your code if you expect others to read it. – Lundin Sep 13 '16 at 08:36
  • @IljaEverilä By "aliasing" you mean "alignment"? – Marko Topolnik Sep 13 '16 at 08:36
  • Could you please replace %d with %hh in the C code and provide an example of the output that you see? It would also be beneficial to see what array processing code do you have in the C part. – Ivan Mushketyk Sep 13 '16 at 08:37
  • @MarkoTopolnik Probably _strict aliasing rule_, I guess. – LPs Sep 13 '16 at 08:38
  • The C code is so broken, it's hard to decide where to begin explaining what's wrong. – Marko Topolnik Sep 13 '16 at 08:42
  • @MarkoTopolnik and @/IljaEverilä I have edited the question with some more details. I will do that and see what the output is. (I cannot add more than one user on my comment) – Sood Sep 13 '16 at 08:46
  • 1
    `ptr1 = (void *)calloc(1, sizeof(int)); ... recv(connected,ptr1,10,0);` You allocate 4 bytes, then allow `recv` to read 10. Just one example. – Marko Topolnik Sep 13 '16 at 08:48
  • Do not [cast the result of malloc and friends](http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc). It serves just to hide possible errors. You still have not shown the declaration of *ptr1*, hence the type is unknown to us. As @MarkoTopolnik pointed out, your code is beyond repair. – Ilja Everilä Sep 13 '16 at 08:51
  • @IvanMushketyk I used %hh instead of %d. I used to get something like `Inc: 5` but now I get `Inc: ` It does not print anything out. – Sood Sep 13 '16 at 08:52
  • @IljaEverilä From your initial comment, since DataOutputStream is only writing one byte, then I can safely ignore all other bytes so that takes care of one problem. However, I am just curious to know what is the alternative to getting say an integer or a byte from a void pointer? Or instead of a void pointer can I create a unsigned char pointer instead, and will that work? – Sood Sep 13 '16 at 09:01
  • 2
    `memcpy` is the safe idiom. http://stackoverflow.com/questions/544928/reading-integer-size-bytes-from-a-char-array – Marko Topolnik Sep 13 '16 at 09:05

1 Answers1

0

The problem with my code was in this line as rightly pointed out in the comments

bytes_received = recv(connected,ptr1,10,0);

I was mistakenly trying to read more than 4 bytes which is the exact number needed to convert to an integer value.

Alternatively, to read 4 and only 4 bytes, this could be written as

bytes_received = recv(connected, ptr1, 4, 0|MSG_WAITALL);

On the java side, again as pointed out in the comments, the function write(int) only sends 1 byte.

To send multiple bytes first the integer must be converted into a 4 byte array, and then each byte in the array must be sent like this

outToClient.write(rlen_array, 0, 4);

Sood
  • 149
  • 1
  • 1
  • 11