Hello,
Sorry I should have explained my self a bit more clearly.
I am setting up a P2P type distributed processing application, using
java.
The Peers when discovered via Multicast, allow a user to select how
many peers they want to run an application on , and which class file
they want to run.
This class file is read by a FileTransferServer Thread into a byte
array.
The server then waits for the specified number of connections.
When the peers receive a message that they are going to be used, they
attempt to connect to the remote Serving Peer over a TCP Socket using
a RemoteClassLoader class that I have defined. There is a simple
protocol that sends the name of the class being transmitted, the size
in bytes and the data itself. If the data does not arrive intact it is
sent again.
The Linux machines never seem to be able to define the class, wether
it is served by a Linux machine or an NT machine, so it just keeps
requesting a resend.
###########################
The Server code is here:
###########################
public class FileTransferServer extends Thread{
ServerSocket ssocket;
File file ;
int numberToServe;
/** **/
public FileTransferServer( int port , File file , int numberToServe){
try{
if( Debug.DEBUGFILETRANSFERSERVER ){
System.out.println(" FileTransferServer Creating Socket on port "
+ port );
}
ssocket = new ServerSocket( port , 1 );
}
catch( SocketException se ){
System.out.println("FileTransferServer: There appears to be a
socket on " + port + " already");
System.exit(1);
}
catch( IOException ioe ){
System.out.println("FileTransferServer: An IOException occured
opening socket on already");
}
this.file = file;
this.numberToServe = numberToServe;
}
/** Waits for connections ( one at a time at the moment), waits for
the client to send OK then writes the file to the socket. **/
public void run(){
FileInputStream fstream = null;
if( Debug.DEBUGFILETRANSFERSERVER ){
System.out.println("FileTransferServer: Opening file for reading "
+ file.toString() );
}
while( fstream == null){
try{
fstream = new FileInputStream( file );
}
catch( FileNotFoundException fnfe ){
System.out.println("FileTransferServer: that file does not exist
");
System.exit(1);
}
}
// do I need to check wether I have got a huge file???
byte[] bytes = new byte[ (int) file.length() ];
if( Debug.DEBUGFILETRANSFERSERVER ){
System.out.println("FileTransferServer: Reading in " + bytes.length
+ " bytes of data ");
}
int bytesread = 0;
// this shouldn't be a problem , but double checking doesn't hurt.
while( bytesread < ( int ) file.length() ){
try{
bytesread = fstream.read( bytes , 0 , (int) file.length() );
}
catch( FileNotFoundException fnfe ){
System.out.println( "FileTransferServer: The file specified does
not exist.");
System.exit(1);
}
catch( IOException ioe ){
System.out.println( "FileTransferServer: An IOException occured
using this file" );
ioe.printStackTrace();
System.exit(1);
}
finally{
if( fstream != null ){
try{ fstream.close(); } catch( IOException ioe){}
}
}
}
if( Debug.DEBUGFILETRANSFERSERVER ){
System.out.println( "FileTransferServer: Data Read. Accepting
Connections... ");
}
// this is just a basic count we really should have a check list of
Peers that we are expecting to
// contact us....
int numberDelivered = 0;
while( numberToServe > numberDelivered ){
Socket s = null;
BufferedReader breader = null;
BufferedOutputStream bostream = null;
DataOutputStream dstream = null;
PrintWriter pwriter = null;
try{
if( Debug.DEBUGFILETRANSFERSERVER ){
System.out.println("FileTransferServer: NumberDelivered " +
numberDelivered + " of " + numberToServe );
}
s = ssocket.accept();
breader = new BufferedReader( new InputStreamReader(
s.getInputStream() ) );
//bostream = new BufferedOutputStream( );
dstream = new DataOutputStream( s.getOutputStream() );
//should send how many bytes are coming...
int bytesWritten = 0;
boolean done = false;
while( ( bytesWritten < bytes.length ) && !done ){
String response = breader.readLine();
if( response == null ){
break;
}
if( response.equals( "OKSENDNAME" ) ){
String name = file.toString().substring( 0 ,
file.toString().length() - 6);
dstream.writeChars( name + "\n" );
dstream.flush();
if( Debug.DEBUGFILETRANSFERSERVER ){
System.out.println("FileTransferServer: Name Sent");
}
}
else if( response.equals( "OKSENDLENGTH" ) ){
dstream.writeInt( (int) file.length() );
dstream.flush();
if( Debug.DEBUGFILETRANSFERSERVER ){
System.out.println("FileTransferServer: Length Sent");
}
}
else if( response.equals( "OKSENDCLASS" ) ||
response.equals("BADSENDCLASS")){
dstream.write( bytes , 0 , bytes.length );
dstream.flush();
}
else if( response.equals("OKDONE") ){
done = true;
}
}
++numberDelivered;
}
catch(IOException ioe ){
System.out.println( "FileTransferServer: Connection closed");
++numberDelivered;
}
finally{
if( dstream != null ){
try{
dstream.close();
}
catch( IOException ioe ){}
}
if( bostream != null ){
}
if( pwriter != null ){
pwriter.close();
}
if( s != null ){
try{ s.close(); } catch( IOException ioe ){}
}
}
}
}
}
################################################
And here is the RemoteClassLoader class
################################################
public class RemoteClassLoader extends ClassLoader{
Socket socket;
byte[] classBytes;
String className;
public RemoteClassLoader( InetAddress address , int port ){
while( socket == null ){
if( Debug.DEBUGREMOTECLASSLOADER ){
System.out.println( "RemoteClassLoader: Attempting to Connect to "
+ address + " on " + port );
}
try{
socket = new Socket( address , port );
}
catch( SocketException se ){
if( Debug.DEBUGREMOTECLASSLOADER ){
System.out.println( "RemoteClassLoader: Waiting for socket on
Peer " + address + " on Port " + port );
}
}
catch( IOException ioe ){
System.out.println( "RemoteClassLoader: There was an IOException
creating socket on port " + port);
System.exit(1);
}
try{ Thread.sleep( 4000 ); } catch( InterruptedException ie ){}
}
if( Debug.DEBUGREMOTECLASSLOADER ){
System.out.println("RemoteClassLoader: Socket " + socket.toString()
+ " created on port " + socket.getLocalPort() + " \n" +
"is connected to " + socket.getInetAddress() + " on port " +
socket.getPort() );
}
}
private Class getRemoteFile(){
Class result = null;
try{ //new BufferedInputStream(
DataInputStream dstream = new DataInputStream(
socket.getInputStream() );
PrintWriter pwriter = new PrintWriter( socket.getOutputStream() ,
true );
pwriter.println( "OKSENDNAME" );
className = "";
char nextchar = '\n';
while( (nextchar = dstream.readChar() ) != '\n'){
className = className.concat( (new Character(nextchar)).toString()
);
}
if( Debug.DEBUGREMOTECLASSLOADER ){
System.out.println( "RemoteClassLoader: Recieved class name " +
className );
}
pwriter.println( "OKSENDLENGTH" );
int length = dstream.readInt();
classBytes = new byte[ length ];
if( Debug.DEBUGREMOTECLASSLOADER ){
System.out.println( "RemoteClassLoader Received File Length " +
length);
}
pwriter.println( "OKSENDCLASS");
pwriter.flush();
int bytesRead = 0;
boolean complete = false;
while( !complete ){
bytesRead = dstream.read( classBytes , 0 , classBytes.length );
if( bytesRead < classBytes.length ){
pwriter.println( "BADSENDCLASS");
}
else{
try{
result = defineClass( className , classBytes , 0 ,
classBytes.length );
pwriter.println( "OKDONE ");
complete = true;
}
catch( ClassFormatError cfe ){
System.out.println("Broken Class file requesting resend.");
pwriter.println("BADSENDCLASS");
}
}
}
if( Debug.DEBUGREMOTECLASSLOADER ){
System.out.println( "RemoteClassLoader Received " + bytesRead + "
bytes" );
}
}
catch( IOException ioe ){
System.out.println("RemoteClassLoader: IOEexception thrown opening
readers on Socket " );
ioe.printStackTrace();
}
finally{
if( socket != null ){
try{ socket.close(); }catch( IOException ioe ){}
}
}
return result;
}
public Class retrieveClass(){
if( Debug.DEBUGREMOTECLASSLOADER ){
System.out.println("RemoteClassLoader: Starting Download");
}
return getRemoteFile();
}
}
################################################## #
I have tried compiling the class file I am sending on both a linux
machine and an NT machine, just in case something funky was happening
but I seem to get the same result.
The problem only seems to occur when, a linux machine is serving the
class. The NT Machines can always read the class and instantiate an
object from it.
The linux machines can instantiate the class only if it is served by
an NT machine.
I am a little confused by this. It seems like an odd bug to have.
Unless I am ding something daft and have gone code blind ( Which
wouldn't be th first time ).
Thanks for your help.
Matthew Melton
|