RMI compressed socket without GZIP ZIP Streams
Hello !
I'm working on a RMI project using compressed sockets
I read a lot first and it seems to be impossible to compress a socket with (G)ZIP streams because RMI use byte mode to communicate and (G)ZIP streams are in block mode.
so, the best solution I see in this forum is to try to implement your own compressing method to create a compressed byte mode stream.
but it's hard and takes a long time to do it.
so I try something more simple unsing inflater/deflater
It works fine, I print a lot of bytes to control the communication and it seems to be ok ...until the DGC startsand hang up the application !
and I don't now why !
the code is based on the example of XOR socket
http://java.sun.com/j2se/1.4.2/docs/guide/rmi/socketfactory/index.html
I only post the compressedStream files
CompressedOutputStream.java
package serveur;
import java.io.FilterOutputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.util.zip.*;
publicclass CompressedOutputStreamextends FilterOutputStream
{
public CompressedOutputStream(OutputStream out)
{
super(out);
}
publicvoid write(byte[] b,int off,int len)throws IOException
{
// print data to be sended
for(int i=0 ; i<len ; i++ )
{
System.out.print(" r"+(int)(b[i]));
}
System.out.println("");
// compress
byte[] tab =newbyte[b.length];
Deflater compresser =new Deflater();
compresser.setInput(b,off,len);
compresser.finish();
int taille = compresser.deflate(tab);
System.out.println("--compressed--");
// print compressed data
for(int i=0 ; i><taille ; i++ )
{
System.out.print(" c"+(int)(tab[i]));
}
System.out.println("");
// send
try
{
System.out.println("\nenvoie "+taille+" ("+len+")\n\n");
out.write(tab,0,taille);
//out.write(b,off,len); // send uncompressed data
}
catch( Exception e )
{
e.printStackTrace();
}
}
}
CompressedInputStream.java
package serveur;
import java.io.FilterInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.util.zip.*;
publicclass CompressedInputStreamextends FilterInputStream
{
public CompressedInputStream(InputStream in)
{
super(in);
}
publicint read(byte b[],int off,int len)throws IOException
{
byte[] tab =newbyte[b.length];
int taille = in.read(tab,off,len);
// read uncompressed data
//int taille = in.read(b,off,len);
//return taille;
//////////////
System.out.println(" \ntaille lue = "+taille);
if( taille < 1 )
{
return taille;
}
// print readed compressed data
for(int i=off ; i<off+taille ; i++)
{
System.out.print(" r"+tab[i]);
}
System.out.println("");
// uncompress
Inflater decompresser =new Inflater();
decompresser.setInput(tab, off, len);
int numBytes = 0;
try
{
numBytes = decompresser.inflate(b);
System.out.println("--uncompressed--");
}
catch( Exception e )
{
e.printStackTrace();
}
decompresser.end();
// print uncompressed data
for(int i=0 ; i><numBytes ; i++)
{
System.out.print(" d"+b[i]);
}
System.out.println("");
System.out.println("\nread block "+numBytes +" off "+off+" len " +len+"\n\n***\n" );
return numBytes;
}
}
>
[7311 byte] By [
DarkTwina] at [2007-11-27 2:59:42]

# 2
I know that it's a bit useless, but it's a school project and I try different things such as crypted socket, compressed socket, ssl socket,etc
> "RMI won't write in chunks of more than 4096 bytes at a time"
are sure, I thought it was 8192, the var len in read methods have always the value 8192
>"and that doesn't compress at all"
for short data, the compressed size is bigger ... logical !
but for data > ~200 bytes it really compress, even if the profit is not significant .
> " you're probably better off compressing them before passing them as arguments "
good idea, you're right, it would be better !
but my question is not about the utility of compressed data, I want to understand why it works only until the DGC starts.
# 3
> > "RMI won't write in chunks of more than 4096 bytes
> at a time"
> are sure, I thought it was 8192, the var len in read
> methods have always the value 8192
Those two statements aren't inconsistent, but you're right. RMI uses BufferedInputStreams and BufferedOutputStreams with 8192-byte buffers.
As to why it works 'only until DGC starts', there's no reason why DGC should break this code. There are several bugs in your CompressedInputStream however:
byte[] tab = new byte[b.length];
The array length here should be 'len', the parameter supplied, which could be < b.length, especially if offset > 0.
int taille = in.read(tab,off,len);
Using either 'off' or 'len' here is futile. Use zero and tab.length, or better still just omit them.
decompresser.setInput(tab, off, len);
Same here.
numBytes = decompresser.inflate(b);
Now here is a bad bug. Here you are ignoring both 'off' and 'len' at a point where you definitely must use them. If offset > 0 this code will definitely fail - it will read the decompressed data into the wrong part of the array. Same applies to the loop where you print the uncompressed data out: it should run from 'off' to 'off+numBytes-', not 0 to numBytes-1.
ejpa at 2007-7-12 3:40:18 >

# 4
thanks to you ejb now it's working fine !
byte[] tab = new byte[b.length];
I wrote it in the outputstream because the size of the compressed data could be bigger than the original ... and then I copy/paste in the inputstream ( mistake ! )
and the bug was in this line
numBytes = decompresser.inflate(b);
corrected by
numBytes = decompresser.inflate(b,off,len);
so RMI wasn't able to read correct data and break ( no problem with DGC )
so now, for anyone who need, there is a simple way to code a compressed socket for RMI
CompressedOutputStream.java
import java.io.FilterOutputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.util.zip.*;
public class CompressedOutputStream extends FilterOutputStream
{
public CompressedOutputStream(OutputStream out)
{
super(out);
}
public void write(byte[] b,int off,int len) throws IOException
{
System.out.println(" readed data size="+len+" ");
for( int i=off ; i<off+len ; i++ )
{
System.out.print(" "+b[i]);
}
System.out.println("");
byte[] tab = new byte[b.length];
Deflater compresser = new Deflater();
compresser.setInput(b,off,len);
compresser.finish();
int taille = compresser.deflate(tab);
System.out.println(" compressed data size="+taille+" ");
for( int i=0 ; i><taille ; i++ )
{
System.out.print(" "+tab[i]);
}
System.out.println("");
System.out.println("\n send data size="+taille+"("+len+") \n\n");
out.write(tab,0,taille);
}
}
CompressedInputStream.java
import java.io.FilterInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.util.zip.*;
public class CompressedInputStream extends FilterInputStream
{
public CompressedInputStream(InputStream in)
{
super(in);
}
public int read(byte b[], int off, int len) throws IOException
{
byte[] tab = new byte[len];
int taille = in.read(tab);
if( taille >< 1 )
{
System.out.println(" nothing readed ! ");
return taille;
}
System.out.println(" readed data size="+taille+" ");
for( int i=0 ; i<taille ; i++)
{
System.out.print(" "+tab[i]);
}
System.out.println("");
Inflater decompresser = new Inflater();
decompresser.setInput(tab);
int numBytes = 0;
try
{
numBytes = decompresser.inflate(b,off,len);
}
catch( DataFormatException e )
{
e.printStackTrace();
}
decompresser.end();
System.out.println(" uncompressed data size="+numBytes+" ");
for( int i=off ; i><off+numBytes ; i++)
{
System.out.print(" "+b[i]);
}
System.out.println("");
System.out.println("\n received data size="+numBytes +"("+taille+")\n\n*************************\n" );
return numBytes;
}
}
>