1

I am trying to send bytes from Android phone to my Raspberry Pi. When i sent it over, I received some weird symbols in this form: 5000 + weird symbols. Bytes should only be in numeric form when received right?

This is my code on Android.

socket.getOutputStream().write(String.valueOf("5000").getBytes());

And this is my code for receiving on Raspberry Pi.

char Buffer[1024];
nread = recv(clientSocket,Buffer,1024,0);
printf("Data Received: %s",Buffer);

Clearly, I am very new to sockets. Also, the bytes I am currently sending in java should = the bytes I am receiving on RPI? Will be really grateful if someone can explain it to me !

Learning2code
  • 51
  • 2
  • 11

4 Answers4

1

The code socket.getOutputStream().write(String.valueOf("5000").getBytes()); sends 4 bytes, because Java use 16 bits chars ONLY for non ASCII character as specified in Java Language Specification 3.10.5.

To be sure, you have to print the value of nread in C program.

The code nread = recv(clientSocket,Buffer,1024,0); receives 4 characters and DOESN'T put the zero to terminate the string, so printf display the contents of the (non initailized) buffer, I suggest memset( Buffer, 0, sizeof( Buffer ))

Code suggested:

if( nread < 0 ) {
   perror("Read error");
   return;
}
Buffer[nread] = '\0';

To encode and decode messages and streams I usually use java.nio.ByteBuffer

To encode and send ASCII 7 java.lang.String:

import java.nio.ByteBuffer;

public final class SerializerHelper {

   public static void putString( String s, ByteBuffer target ) {
      final byte[] bytes = s.getBytes();
      target.putInt( bytes.length );
      target.put( bytes );
   }

   public static void putBoolean( boolean value, ByteBuffer target ) {
      target.put((byte)( value ? 1 : 0 ));
   }

   public static boolean getBoolean( ByteBuffer source ) {
      return source.get() != 0;
   }

   public static String getString( ByteBuffer source ) {
      final int len = source.getInt();
      final byte[] bytes = new byte[len];
      source.get( bytes );
      return new String( bytes );
   }
}

In C:

uint32_t len       = strlen( s );
uint32_t lenForNet = htonl( len );
char * p = buffer;
memmove( p, &lenForNet, sizeof( lenForNet ));
p += sizeof( lenForNet );
memmove( p, s, len );
send( sckt, buffer, len + sizeof( LenForNet ), 0 );
Aubin
  • 14,617
  • 9
  • 61
  • 84
  • Worth mentioning that it's still a good idea to include the charset when getting the bytes to avoid surprises when a user *does* include non-ASCII characters in the input – cbr May 16 '17 at 06:38
  • Sorry I don't get it, so do i use memset or the code you suggested? – Learning2code May 16 '17 at 06:46
  • 'I suggest memset( Buffer, 0, sizeof( Buffer ))' - why would you suggest that waste of cycles when you already know where to put the NUL - [nread]. – ThingyWotsit May 16 '17 at 07:31
  • You have to initialize all the variables before use, in C language. After a call, you have to check the return code because exceptions doesn't exists in C. `nread` maybe negative or nul. recv may read less character than you expect. See man recv. – Aubin May 16 '17 at 07:31
  • 'The code nread = recv(clientSocket,Buffer,1024,0); receives 4 characters' no, it does not have to. It receives no more than 1024 bytes, but may receive less. If 4 characters are sent, there is no guarantee that a call to recv() will load all the bytes representing the four chars into the buffer in one call. – ThingyWotsit May 16 '17 at 07:35
  • 'You have to initialize all the variables before use,' no, not if you first use is to load them - that, in itself, is an initialization. The memset/bzero/whatever of large comms buffers is just cargo-cult programming that wastes cycles for no gain. – ThingyWotsit May 16 '17 at 07:35
  • With 'nread = recv(clientSocket,Buffer,1024,0);' and 'Buffer[nread] = '\0';', the receipt of all 1024 bytes would result in an out-of-bounds write of the NUL. Either read [1024-1] or oversize the buffer to [1025]. – ThingyWotsit May 16 '17 at 07:39
  • @Aubin Hi Aubin, this time, I am trying to send string from C to Java. How should I convert it such that it receives properly in Java? – Learning2code May 25 '17 at 08:23
  • @Aubin Thank you so much! – Learning2code May 26 '17 at 06:44
0

Strings in Java are 16 bits. If you want to send a string to C, convert to utf-8 first. (Or use a 16 bit string library, but generally you'd convert to utf8).

Gabe Sechan
  • 90,003
  • 9
  • 87
  • 127
  • oh i see! Okay I will try it after lunch. How do i know what buffer size i should set for the string? – Learning2code May 16 '17 at 05:05
  • No, consult : http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.5 – Aubin May 16 '17 at 05:16
  • @Aubin just read it. It says nothing about character encoding in that section. I've never heard about java using 8 bit characters anywhere under any circumstances, and if it did whay you said I know quite a bit of code that works in the wild would be broken. I think you misread the past on it handling characters that take more than 1 16 bit characters to be more than 1 8 bit characters – Gabe Sechan May 16 '17 at 05:22
  • 1
    I did a conversion by doing: socket.getOutputStream().write(String.valueOf(progress).getBytes("UTF-8")); But it didn't work – Learning2code May 16 '17 at 06:45
  • See http://stackoverflow.com/questions/7921016/what-does-it-mean-to-say-java-modified-utf-8-encoding – Aubin May 16 '17 at 07:34
0

I solved the problem. After searching and looking around stackoverflow, I followed the answer from this link. Here

I did:

Buffer[nread] = '\0';
printf("%s",Buffer);
Community
  • 1
  • 1
Learning2code
  • 51
  • 2
  • 11
0

Receiving from socket

char recv_data;
 while ((bytes_received = recv(connected,&recv_data,1,0)) > 0){
        printf("\nrecv= %c\n", recv_data);
        }

Sending from Java

 String datatosend = "5000";
   char[] strArray;
   strArray = datatosend.toCharArray();

   while (true) {
   for( int index = 0; index < strArray.length; index++){
       out.write(strArray[index]);
   }
out.flush();
Deb S
  • 509
  • 5
  • 16