Why socket just dumped between Android and Linux? - java

In my case,Android App should be regarded as a Server and linux is the client.
I just send data from linux to Android with 4096 bytes per send.
The log shows that linux sends all data successfully.
Here come to the Server, i.e Android...
Server receives data with 4096 bytes per receive. But socket error happened because the read(...) function return the value -1;
Here is my code:
In linux with c++:
auto size = static_cast<int>(buffer.size()); // buffer is the data needed to send;
auto bytes_send = 0, bytes = 0;
printf("target. data size needed to send: %d\n", size);
int single = 4096;
while(bytes_send < size){
int remain = size - bytes_send;
if(remain < single){
bytes = send(socket_client_fd, &buffer[bytes_send], remain, 0);
} else {
bytes = send(socket_client_fd, &buffer[bytes_send], single, 0);
}
if(bytes < 0){
std::cerr:: "Failed to send data" << std::endl;
return;
}
bytes_send += bytes;
printf("This remain: %d; We send %d bytes; Totally %d bytes sended;\n", remain, bytes, bytes_send);
}
And the server with java:
// previously got size need to receive
byte[] bytes = new byte[size];
int bytes_recved = 0;
int single = 4096;
while(bytes_recved < size){
int remain = size - bytes_recved;
int read = -1;
if(remain < single)
read = inputStream.read(bytes, bytes_recved , remain);
else
read = inputStream.read(bytes, bytes_recved , single);
if(read < 0){
Log.i(TAG, "received failed, less than 0 bytes " + read);
break;
}
bytes_recved += read;
Log.i(TAG, "received: " + bytes_recved + " ; receive this time: " + read);
}
Client send all data completely, but Server failed to received data, here is the log of Server(Android),It seems that data just lost! I think my code is right, but why it failed?
Here is the log of server:
The log of Server(Android)

The logical mistake is this:
if(readed < 0)
It should be:
if(read < 0)
I advise you to use better variable names. The past participle of read is read not readed.

Related

Read Socket Packets correctly from Sb0t Chat Server with Java

My question is about Java. I am trying to receive a package called MSG_CHAT_SERVER_PUBLIC from a chat server. This package contains the user's name and the message that he sends.
The protocol is in this list of protocols: http://uruguayos-xtremos2011.blogspot.com/p/ares-protocol-aresnuevo.html?m=1
In the Public method you can see how the server forms the package: https://github.com/AresChat/sb0t/blob/128b2755cdfedaf498d66fbcdf9fda010f4d3087/core/TCPOutbound.cs
In the Service method you can see how a chat client receives the packets: https://github.com/AresChat/cb0t/blob/master/cb0t/RoomPanel/AresSocket.cs
In the Eval_Public method you can see how the package is read in the Chat Client: https://github.com/AresChat/cb0t/blob/master/cb0t/RoomPanel/Room.Handler.cs
I have the following as code (but no read package appears in the EditText; I expect the opposite):
InputStream in = sock.getInputStream();
while (sock.isConnected()) {
// get message length, first 2 bytes
byte[] lengthBytes = new byte[2];
in.read(lengthBytes);
// convert to int
int messageLength = lengthBytes[0] << 8 | lengthBytes[1];
// get the protocol byte
int procotol = in.read();
// get message, length bytes
byte[] messageBytes = new byte[messageLength];
s.chat.append(Integer.toString(in.read(messageBytes)));
// separate message, first x bytes are username
int length = 0;
// get username length
for (byte messageByte : messageBytes) {
if (messageByte == 0) break;
length++;
}
// extract username
byte[] username = new byte[length];
System.arraycopy(messageBytes, 0, username, 0, length);
int pos = length + 1;
// message length
length = messageBytes.length - pos;
// extract message
byte[] message = new byte[length];
System.arraycopy(messageBytes, pos, message, 0, length);
s.chat.append("message length: " + messageLength + "\nprocotol: " + procotol + "\nusername: " + new String(username) + "\nmessage: " + new String(message));
}
Maybe it will be easier for you if I tell you what I've made so far: https://1drv.ms/u/s!An2GIBqaxDQCgTZ_PCnapHpoRjny
Thanks in advance for your help

Java client to C# server TCP

The problem is when i send up to 40 KB everything is okay when i send more sometime half of the data received some time nothing ,is there a limit of the networkstream.Read ,even though i cunked the data ,i can't determine if the problem form the java or the c# from the network stream or the Output stream
C# SERVER
private void ReadData(){
if (networkStream.DataAvailable)
{
int size = GetBufferSize();
Thread.Sleep(340);
byte[] myReadBuffer = new byte[size];
int numberOfBytesRead = 0;
while (true)
{
numberOfBytesRead = networkStream.Read(myReadBuffer, 0, myReadBuffer.Length);
if (numberOfBytesRead >= myReadBuffer.Length)
{
break;
}
}
string str = Encoding.UTF8.GetString(myReadBuffer, 0, size);
dynamic Message = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(str);
// Android Message , JSON String
if (OnAndroidMessage != null)
{
OnAndroidMessage(Message);
}
}
}
private int GetBufferSize()
{
byte[] myReadBuffer = new byte[4];
int numberOfBytesRead = 0;
do
{
numberOfBytesRead = networkStream.Read(myReadBuffer, 0, myReadBuffer.Length);
} while (networkStream.DataAvailable && numberOfBytesRead < myReadBuffer.Length);
if (numberOfBytesRead > 0)
{
// reverse the byte array.
if (BitConverter.IsLittleEndian)
{
Array.Reverse(myReadBuffer);
}
return BitConverter.ToInt32(myReadBuffer, 0);
}
else
{
return 0;
}
}
Java Client // i tested this also without cutting the data to smaller paces ,half of the data received not all of them
mBufferOut = socket.getOutputStream();
private void sendMessage(final String message) {
if (mBufferOut != null && message != null) {
try {
byte[] data = message.getBytes("UTF-8");
Log.d("_TAG", "Sending: " + message);
Log.d("_TAG", "Message length: " + Integer.toString(data.length));
mBufferOut.write(toByteArray(data.length));
mBufferOut.flush();
List<byte[]> divideArray = divideArray(data, 10000);
for (byte[] dataChunk : divideArray) {
Log.e("_TAG","CHUNK SIZE > " + Integer.toString(dataChunk.length));
mBufferOut.write(dataChunk, 0, dataChunk.length);
mBufferOut.flush();
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
private List<byte[]> divideArray(byte[] source, int chunksize) {
List<byte[]> result = new ArrayList<byte[]>();
int start = 0;
while (start < source.length) {
int end = Math.min(source.length, start + chunksize);
result.add(Arrays.copyOfRange(source, start, end));
start += chunksize;
}
return result;
}
Any ideas ?
Solution from this post NetworkStream is reading data that should not be there
static void ReadExact(Stream stream, byte[] buffer, int offset, int count)
{
int read;
while(count > 0 && (read = stream.Read(buffer, offset, count)) > 0) {
offset += read;
count -= read;
}
if(count != 0) throw new EndOfStreamException();
}
the problem is the Read it takes size and want to get that size you need to give it chunks and check each chunk
And also read does not restart from where it stopped until it reads the amount is set to read meaning if i set to read 10 then if it not find the 10 then it will read what it find as example it reads 6 ,it will return 6 and when to loop another time ti read the rest it dose not start from 6 it start from 0 and read until 4 so you overwrite your data ,and if it read 10 from the first try then it set the read to finish so it dose not start from 0 ,it needs to read the amount the has been set to it to re set the read to new buffer location.

It is possible when inputStream.available != 0 the complete data has not been received?

I am using a BluetoothSocket in Android (in spp mode). I send data like this:
Packet sent﹕ 0xAA 0x00 0x00 0x01 0x01 0x14 0x00 0x00 0xB6 0x34
and i get response:
Packet received﹕ 0xAA 0x01 0x00 0x01 0x81 0x14 0x00 0x00 0x8F 0x34
But when I try to get a large response, I get the following error:
09-25 11:13:26.583 6442-6495E/AndroidRuntime﹕ FATAL EXCEPTION: Thread-1258
Process: es.xxx.xxxx, PID: 6442
java.lang.ArrayIndexOutOfBoundsException: length=178; index=178
The error is in:
public void receive(int command, byte[] data) {
if (data.length != 0) {
int device = data[1];
int par = data[5];
short sizeData = (short)(((data[6]&0xFF) << 8) | ((data[7]&0xFF)));
byte[] datos = new byte[sizeData];
for (int i = 0; i < sizeData; i++) {
datos[i] = data[8 + i]; // Here ocurred the error
}
switch (command) {
case RETURN_PING:
break;
case RETURN_MOUNT:
...
}
My method in order to read input data from bluetooth is (I made manual timeout following a response in StackOverflow):
public byte[] read(){
try {
int timeout = 0;
int maxTimeout = 10; // leads to a timeout of 2 seconds
int available = 0;
while((available = in.available()) == 0 && timeout < maxTimeout){
timeout++;
Thread.sleep(50);
}
receive = new byte[available];
in.read(receive);
return receive.clone();
} catch (IOException e) {
e.printStackTrace();
if (socket != null){
close();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
So, my question is: It is possible when in.available != 0 the complete data has not been received yet? (in this way, method receive read bytes 6 and 7, where is store the packet lenght, but when this method try to iterate over all items it throw ArrayIndexOutOfBoundsException).
The major problem of your "read" is incorrect computing of how many bytes need to be read to get the whole package. There is a few main solutions how to pass and, then, read a data packet:
a. each packet has a header with its length specified
b. each packet has a predefined delimiter at its end, a kind of magic like "0x00" (this means you cannot use this byte in your data)
c. some other exotic ones
As I see, you use a. Then you may use something like this:
/**
* equals to java.io.DatainputStream.readFully
*/
public static void readFully(InputStream in, byte b[], int off, int len) throws IOException {
if (len < 0) {
throw new IndexOutOfBoundsException();
}
int n = 0;
while (n < len) {
final int count = in.read(b, off + n, len - n);
if (count < 0) {
throw new EOFException();
}
n += count;
}
}
public static int readByte (byte [] bytes, int offset) {
return ((int) bytes [offset]) & 0xFF;
}
public static short readShort(byte [] bytes, int offset) {
return (short)
(readByte(bytes, offset) << 8 |
readByte(bytes, offset + 1));
}
I see your header consists of 8 bytes. Then I'd suggest to do the following:
byte[] header = new byte[8];
readFully(in, header, 0, header.length);
int device = readByte(header, 1);
int par = readByte(header, 5);
int sizeData = readShort(header, 6);
byte[] data = new byte[sizeData];
readFully(in, data, 0, sizeData);
// now we have the whole data
After years of development I still have no a good idea what would we do with InputStream.available() :) To close a connection by data transmission timeout you could use
http://docs.oracle.com/javase/7/docs/api/java/net/Socket.html#setSoTimeout(int)
or if not available, as in your case, a kind of timer
http://developer.android.com/reference/java/util/Timer.html
(update last receiving time after each call of readFully method and check the difference between current time and last receiving time by the timer)
It is possible when inputStream.available != 0 the complete data has not been received?
There is nothing in its Javadoc that says anything about 'complete data'. The Javadoc correctly states that it is a measure of how much data may be read without blocking.
It isn't:
a measure of the total length of the input stream
an indicator of message boundaries
an indicator of end of stream.
The Javadoc contains a specific warning about using its value to allocate a buffer ...
If you want a read timeout, use Socket.setSoTimeout().

Java NIO Serialization StreamCorruptException Invalid Type Code

I'm trying to transfer an object from a client (normal IO) to a server (NIO).
Transmission works fine until the object reaches a certain size, then the server will throw a "StreamCorruptException" saying "invalid type code".
The method called on the server is the following:
private void read(SelectionKey key) throws IOException, ClassNotFoundException {
SocketChannel chan = (SocketChannel) key.channel();
//read message object
ByteBuffer buf = ByteBuffer.allocate(1024);
ByteArrayOutputStream bos = new ByteArrayOutputStream(buf.capacity());
int length = 0;
int totalRead = 0;
int read = chan.read(buf);
System.out.println("read data " + read);
if (read >= 4) {
length = IoUtil.readInt(buf.array(), 0);
bos.write(buf.array());
buf.rewind();
totalRead += read;
LogUtil.log("length of data message is " + length);
}
while (totalRead < length) { //read until we get no more data
read = chan.read(buf);
if (read == -1) break;
if (read == 0) continue;
totalRead += read;
System.out.println("I've read " + read + " bytes. Total amount of bytes " + totalRead);
bos.write(buf.array());
buf.rewind();
}
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray(), 4, length);
ObjectInputStream inFromClient = new ObjectInputStream(bis);
Message msg = (Message) inFromClient.readObject();
SocketAddress sa = chan.socket().getRemoteSocketAddress();
LogUtil.log(msg.getIdentifier() + "-Message von " + sa);
commData.handleMessage(sa, msg);
}
I prepend the size of the object to make NIO play nicely.
What am I missing here?
You have to consider that a message can be fragmented (which is what I suspect is happening here) or coalessed. This means you cannot assume that the start of a message and end of a message will be at the start or end of a read. (It typically is for small messages with a significant break between them, but this fails randomly)
The safe approach is to send a length at the start and read until you have that length. If you have more, keep the extra for the next read.

Ensuring no packet loss between TCP client and server

I am writing a Java TCP client which sends chunks of data to a C server. The client-server worked very well on my development PC. This code upon deployment on a hardware board showed packet loss. I only have the logs with me and I know that the server did not receive all packets.
I do not have the hardware to test. Therefore, at the first level, I want to be very sure client code does send all the required data.
Here is my code(the client part in Java). How do I make sure this is done? Is there some resend commands with timings etc?
Socket mySocket = new Socket("10.0.0.2",2800);
OutputStream os = mySocket.getOutputStream();
System.out.println(" Sending 8 byte Header Msg with length of following data to Server");
os.write(hdr, 0, 8);
os.flush();
System.out.println(" Sending Data ");
start = 0;
for(int index=0; index < ((rbuffer.length/chucksize)+1); index++){
if(start + chucksize > rbuffer.length) {
System.arraycopy(rbuffer, start, val, 0, rbuffer.length - start);
} else {
System.arraycopy(rbuffer, start, val, 0, chucksize);
}
start += chucksize ;
os.write(val,0,chucksize);
os.flush();
}
Here is the C snippet which receives this data:
while ((bytes_received = recv(connected, rMsg, sizeof(rMsg),0)) > 0){
if (bytes_received > 0) // zero indicates end of transmission */
{
/* get length of message (2 bytes) */
tmpVal = 0;
tmpVal |= rMsg[idx++];
tmpVal = tmpVal << 8;
tmpVal |= rMsg[idx++];
msg_len = tmpVal;
len = msg_len;
//printf("msg_len = %d\n", len);
printf("length of following message from header message : %d\n", len);
char echoBuffer[RCVBUFSIZE] ;
memset(echoBuffer, 0, RCVBUFSIZE);
int recvMsgsize = 0;
plain=(char *)malloc(len+1);
if (!plain)
{
fprintf(stderr, "Memory error!");
}
for( i = RCVBUFSIZE; i < (len+RCVBUFSIZE); i=i+RCVBUFSIZE){
if(i>=len){
recvMsgSize = recv(connected, echoBuffer, (len - (i-RCVBUFSIZE)), 0);
memcpy(&plain[k], echoBuffer, recvMsgSize);
k = k+recvMsgSize;
}
else{
recvMsgSize = recv(connected, echoBuffer, RCVBUFSIZE, 0);
memcpy(&plain[k], echoBuffer, recvMsgSize);
k = k+recvMsgSize;
}
}
}//closing if
}//closing while
First of all there is no such thing as packet loss in TCP/IP. This protocol was designed to reliably send a stream of bytes in correct order. So the problem must be with your application or the other side.
I am not really in a mood to analyze this whole arraycopy() madness (C anyone?), but why aren't you just sending the whole rbuffer in one go through BufferedOutputStream?
OutputStream os = new BufferedOutputStream(mySocket.getOutputStream());
and then:
os.write(rbuffer);
Believe me, BufferedOutputStream is doing the exact same thing (collecting bytes into chunks and sending them in one go). Or maybe I am missing something?
I changed the C side program in the following way and it now works:
printf("length of following message from header message : %d\n", len);
plain=(char *)malloc(len+1);
if (!plain)
{
fprintf(stderr, "Memory error!");
}
memset(plain, 0, len+1);
int remain = len;
k= 0;
while (remain){
int toGet = remain > RCVBUFSIZE ? RCVBUFSIZE : remain;
remain -= toGet;
int recvd = 0;
while(recvd < toGet) {
if((recvMsgSize = recv(connected, echoBuffer, toGet-recvd, 0)) < 0){
printf("error receiving data\n");
}
memcpy(&plain[k], echoBuffer, recvMsgSize);
k += recvMsgSize;
printf("Total data accumulated after recv input %d\n", k);
recvd += recvMsgSize;
}
}

Categories