?
Solved

Socket Programming

Posted on 2003-02-26
30
Medium Priority
?
273 Views
Last Modified: 2008-01-09
I have a client and server. The client has to read a file in blocks and send it over as the block is filled. The server reads in the blocks and writes out the data to a file. There is no assumption that the data is ASCII text or contains any newlines.

A part of my code is for Server.java is:
DataInputStream input = new DataInputStream(mySocket.getInputStream());
File file = new File("whatever");
byte[] filebyte = new byte[16];
FileOutputStream fileOS = new FileOutputStream(file);
int length;

while((length = input.read(filebyte)) != -1)
{
    fileOS.write(filebyte);
}
fileOS.close();
input.close();

Part of the code from Client.java is:
byte[] buf = new byte[16];
File file = new File(filename);
FileInputStream fileIS = new FileInputStream(file);
while(fileIS.read(buf) != -1)
{
    output.write(buf);
}
output.writeByte(0);

I am getting a bad file number error on the server side. I'm not sure where to go from here.

-Marvyn
0
Comment
Question by:MarvynDT
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 14
  • 12
  • 4
30 Comments
 
LVL 92

Expert Comment

by:objects
ID: 8030328
You are ignoring the number of bytes that are actually read on both the client and server sides, and instead writing the whole buffer array regardless.

0
 
LVL 2

Expert Comment

by:functionpointer
ID: 8031012
all of your read/write loops should look a bit like this:
int len = 0;
while ( ( len = is.read( buf ) > -1 )
{
  os.write( buf, 0, len );
}

otherwise you are writing a fistful of nulls to the file. 15:16, that is. you will occasionally get lucky. :-)
0
 

Author Comment

by:MarvynDT
ID: 8031035
Does it matter in this context, considering that both buffer sizes are equal?

I tried adjusting on both, i.e. fileIS.write(buf, offset, length), etc.., but it produced the same error:
java.net.SocketException: socket closed: Bad file number

I was thinking that because both java programs are executed within the same folder, it cannot read and write to the same file at the same time. But I changed the file name in the server program and had the same error produced.
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 92

Expert Comment

by:objects
ID: 8031042
As I had already stated :)

> otherwise you are writing a fistful of nulls to the file.

Not necesarily nulls (assuming you mean 0 when you say null).

0
 
LVL 92

Expert Comment

by:objects
ID: 8031051
from the javadoc for read():

"Reads some number of bytes from the input stream and stores them into the buffer array b. The number of bytes actually read is returned as an integer. "
0
 
LVL 92

Expert Comment

by:objects
ID: 8031059
Your code should look more like this:


A part of my code is for Server.java is:
DataInputStream input = new DataInputStream(mySocket.getInputStream());
File file = new File("whatever");
byte[] filebyte = new byte[16];
FileOutputStream fileOS = new FileOutputStream(file);
int length;

while((length = input.read(filebyte)) != -1)
{
   fileOS.write(filebyte, 0, length);
}
fileOS.close();
input.close();

Part of the code from Client.java is:
byte[] buf = new byte[16];
int length;
File file = new File(filename);
FileInputStream fileIS = new FileInputStream(file);
while((length = fileIS.read(buf)) != -1)
{
   output.write(buf, 0, length);
}

//output.writeByte(0); <- I'm not sure why you do this
0
 

Author Comment

by:MarvynDT
ID: 8031128
functionpointer posted right before I got to read it, and it now makes sense. Taking that advice into my code still produces the bad file number error.

I took the code snippet and adjusted it to my own code. I am still running into the same error. The client is now producing an error: java.io.IOException: Broken Pipe.
And the Server still has the same error.

I'm trying to move at .77KB file across the socket with a 16 byte buffer. Shouldn't I be getting "lucky" about 48 times. I adjusted the client so that it shows the number of bytes read into the buffer are full at 16. It loops throught this twice. Server never loops. It has a problem when it hits the instruction:
while((len=input.read(filebyte)) != -1)

0
 

Author Comment

by:MarvynDT
ID: 8031138
Thanks object. I just compared my code to the modified code that you submitted. But its still producing the errors I listed in my last comment.
0
 
LVL 92

Expert Comment

by:objects
ID: 8031170
better post your complete current code that handles the transfer on both end, everything from when you open the streams to when you close them.

There doesn't seem to be any reason for you to use a DataInputStream though it shouldn't create a problem in the way you use it.

0
 

Author Comment

by:MarvynDT
ID: 8031231
//code for the client:
import java.io.*;
import java.net.*;
import java.lang.*;

public class Put
{
    static int port;
    static String host;
    static String filename;

    public static void main(String[] args)
    {
        String usage = "usage: java Put [-h hostname] [-p portname] filename";

        if(args.length == 0)
        {
            System.err.println(usage);
            System.exit(1);
        }
        else if(args.length == 1
                && !(args[0].equalsIgnoreCase("-h")
                || args[0].equalsIgnoreCase("-p")))
        {
            //check if filename is ASCII compliant
            if(!(isprint(args[0])))
            {
                System.err.println("error in filename: " + args[0]);
                System.exit(1);
            }
            filename = args[0];
            port = 43210;
            host = "localhost";
        }
        else
        {
            int portfoundflag = 0;
            int hostfoundflag = 0;
            for(int argsindex = 0; argsindex < args.length; argsindex++)
            {
                if(args[argsindex].equalsIgnoreCase("-P") && portfoundflag == 0)
                {
                    // -p port
                    portfoundflag = 1;      //set port to found
                    if(++argsindex >= args.length || (argsindex + 1) >= args.length)
                    {
                        System.err.println(usage);
                        System.exit(1);
                    }
                    //check if port number is valid
                    if((port = isportvalid(args[argsindex])) == -1)
                    {
                        System.err.println("port range out of bounds: " + args[1]);
                        System.err.println("range: {1024-65535}");
                        System.exit(1);
                    }
                }
                else if(args[argsindex].equalsIgnoreCase("-H") && hostfoundflag ==0)
                {
                    // -h host
                    hostfoundflag = 1;
                    if(++argsindex >= args.length || (argsindex +1) >= args.length
                        || args[argsindex].equalsIgnoreCase("-P"))
                    {
                        System.err.println(usage);
                        System.exit(1);
                    }
                    host = args[argsindex];
                }
                else if((argsindex + 1) == args.length)
                {
                    // filename
                    //check if filename is ASCII compliant
                    if(!(isprint(args[argsindex])))
                    {
                        System.err.println("error in filename: " + args[argsindex]);
                        System.exit(1);
                    }
                    filename = args[argsindex];
                }
                else
                {
                    System.err.println(usage);
                    System.exit(1);
                }
            }
        }
        senddata();
    }
 
    // send put command to server
    static void senddata()
    {
        try
        {
            // establish connection
            Socket s = new Socket(host, port);
            System.out.println("connecting to " + host + " on " + port);          
 
            DataOutputStream output;
            DataInputStream input;
            byte bytein;
            int resultreceived = 0;
            byte[] buf = new byte[16];
            byte[] filebyte = new byte[50];
            int index = 0;
 
            try
            {
                output = new DataOutputStream(s.getOutputStream());
                output.writeBytes("P");            //instruction
                output.writeBytes(filename);      //filename
                output.writeByte(0);            //eof

                //get confirmation from server
                input = new DataInputStream(s.getInputStream());
                while((bytein = input.readByte()) != 0)
                {
                    if(!(resultreceived == 0))
                    {
                        filebyte[index++] = bytein;
                    }
                    if(bytein == 89 || bytein == 121)
                    {
                        //filename accepted
                        resultreceived = 1;      //answer found
                    }
                    else if(bytein == 78 || bytein == 110)
                    {
                        //filename not accepted
                        System.out.println("server error: " + new String(filebyte));
                        System.exit(1);
                    }
                }

                // read file and send over socket to server
                File file = new File(filename);
                FileInputStream fileIS = new FileInputStream(file);
                int len = 0;
                while((len=fileIS.read(buf)) != -1)
                {
                    System.out.println(len);
                    System.out.println(""+fileIS.available());
                    output.write(buf,0,len);
                }
 
            }
            catch(IOException e)
            {
                System.out.println(e);
            }
        }
        catch(UnknownHostException e)
        {
            System.err.println("unknown host: " + host);
            System.exit(1);
        }
        catch(IOException e)
        {
            System.out.println(e.getMessage());
        }
    }

    // returns true if all chars in string are ASCII compliant
    public static boolean isprint(String s)
    {
        for(int k = 0; k < s.length(); k++)
        {
            char currentchar = s.charAt(k);
            int i = (int)currentchar;
            if(i > 128)
            {
                return false;
            }
        }
        return true;
    }

    // returns -1 if port number is invalid, else returns port number
    public static int isportvalid(String s)
    {
        int port = -1;
        try
        {
            port = (new Integer(s)).intValue();
            if(port > 65535 || port < 1024)
            {
                return -1;
            }
        }
        catch (NumberFormatException e)
        {
            System.err.println("bad number format: " + s);
            System.err.println("usage: java Put [-h hostname] [-p portname] filename");
            System.exit(1);
        }
        return port;
    }
}
0
 

Author Comment

by:MarvynDT
ID: 8031236
//code for the server:

import java.io.*;
import java.net.*;
import java.lang.*;

public class Server
{
    static int port;      //server port

    public static void main(String[] args)
    {
        String usage = "usage: java Server [-p portnumber]\n";

        if(args.length == 0)
        {
            port = 43210;      //hard-wired port number
        }
        else if(args.length == 2 && args[0].equals("-p"))
        {
            try
            {
                port = (new Integer(args[1])).intValue();
                if(port > 65535 || port < 1024)
                {
                    System.err.println("port range out of bounds: " + port);
                    System.err.println("range: {1024-65535}");
                    System.exit(1);
                }
            }
            catch (NumberFormatException e)
            {
                System.err.println("bad number format: " + args[1]);
                System.err.println(usage);
                System.exit(1);
            }
        }
        else
        {
            System.err.println(usage);
            System.exit(1);
        }
        serve();
    }

    // create socket and wait for connections
    public static void serve()
    {
        try
        {
            DataInputStream input;
            DataOutputStream output;
            String filename;
            String command;

            ServerSocket ss = new ServerSocket(port, 5);

            while(true)
            {
                System.out.println("waiting for connection on port " + port);
                Socket s = ss.accept();      //wait instruction
                System.out.println("got a connection from "
                    + s.getInetAddress().getHostAddress()
                    + ", port: " + s.getPort());
                try
                {
                    command = "invalid";      //reset command
                    input = new DataInputStream(s.getInputStream());
                    byte bytein;
                    byte[] filebyte = new byte[16];
                    int index = 0;
                    while((bytein=input.readByte()) != 0)
                    {
                        if(!(command.equals("invalid")))
                        {
                            filebyte[index++] = bytein;
                        }
                        else if(bytein == 80 || bytein == 112)
                        {
                            //put instruction
                            command = "put";
                        }
                        else if(bytein == 71 || bytein == 103)
                        {
                            //get instruction;
                            command = "get";
                        }
                    }
                    filename = new String(filebyte);

                    //check that filename is legit
                    if(isprint(filename))
                    {
                        if(command.equals("put"))
                        {
                            //create new file
                            File file = new File("NEW" + filename);
                            file.createNewFile();
                            sendmessage(s, "Y");
           
FileOutputStream fileOS = new FileOutputStream(file);

int len = 0;
System.out.println("before loop");
while((len=input.read(filebyte)) != -1)
{
    System.out.println(len);
    fileOS.write(filebyte,0,len);
}
fileOS.close();
input.close();

                        }
                        else if(command.equals("get"))
                        {
                            //check that file exists
                            File file = new File(filename);
                            if(file.exists())
                            {
                                sendmessage(s, "Y");
                                sendfile(s, filename);
                            }
                            else
                            {
                                sendmessage(s, "N", "File does not exist");
                            }
                        }
                    }
                    else
                    {
                        sendmessage(s, "N", "Filename not acceptable");
                    }
                }
                catch(IOException e)
                {
                    System.out.println(e);
                }
            }
        }
        catch (java.io.IOException e)
        {
            System.out.println(e.getMessage());
        }
    }

    // returns true if all chars in string are ASCII compliant
    public static boolean isprint(String s)
    {
        for(int k = 0; k < s.length(); k++)
        {
            char currentchar = s.charAt(k);
            int i = (int)currentchar;
            if(i > 128 || i == 47)
            {
                return false;
            }
        }
        return true;
    }

    // send to client, answer with message
    public static void sendmessage(Socket s, String result, String message)
    {
        try
        {
            DataOutputStream output = new DataOutputStream(s.getOutputStream());
            output.writeBytes(result);      //request
            output.writeBytes(message);      //optional message
            output.writeByte(0);            //eof
            output.close();
        }
        catch(IOException e)
        {
            System.out.println(e);
        }
    }
 
    // send to client, answer w/o message
    public static void sendmessage(Socket s, String result)
    {
        try
        {
            DataOutputStream output = new DataOutputStream(s.getOutputStream());
            output.writeBytes(result);      //request
            output.writeByte(0);            //eof
            output.close();
        }
        catch(IOException e)
        {
            System.out.println(e);
        }
    }

    // get file from client on Socket s
    public static void retrievefile(Socket s, String filename)
    {
        byte[] buf = new byte[16];
        int length;

        try
        {
            DataInputStream input = new DataInputStream(s.getInputStream());
            File file = new File(filename);
            FileOutputStream fileOS = new FileOutputStream(file);

            while((length = input.read(buf)) != -1)
            {
                fileOS.write(buf);
            }
            fileOS.close();
            input.close();
        }  
        catch(IOException e)
        {
            System.out.println(e);
        }
    }

    // get file and send to client on Socket s
    public static void sendfile(Socket s, String filename)
    {
    }
}
0
 
LVL 2

Expert Comment

by:functionpointer
ID: 8031245
>> Shouldn't I be getting "lucky" about 48 times?

Shouldn't we all...

what i meant was: unless your reading really slow, the only place you will have less than 16 bytes read into the buffer is on the very last read.  hence, the 1 out of every 16 times the amount will be correct.

>> Server never loops.

hmmm. your file.write() is in that block. try writing each byte to a ByteArrayInputStream instead
while ( ( b = is.read() ) != -1 ) baos.write( b );
dump this to check it out, then write the result to the file later. btw, what is the timeout on the socket?
0
 
LVL 2

Expert Comment

by:functionpointer
ID: 8031302
sorry, was writing while you were posting...

from what you've posted, is seems your sending some ascii on every request/response. HTTP has a decent model of this. It uses CRLF as a header delimiter and CRLF CRLF to delimit data. If you use a model like this, you could use a BufferedReader to strip off ascii header data, then read from the socket's input stream to get the data ( if the header said so ). The nice thing about this is you can know how much data to read by some header like "Content-length: 2435".  Once the header is past, CRLF CRLF, use a BufferedInputStream to read the bytes.
0
 
LVL 92

Expert Comment

by:objects
ID: 8031303
can u also post the debug messages that are displayed when u run it.
0
 
LVL 92

Expert Comment

by:objects
ID: 8031330
You are closing the stream in sendMessage on the server, resulting in the socket getting closed.
Try removing the close().
0
 

Author Comment

by:MarvynDT
ID: 8031338
remus% java Server
waiting for connection on port 43210
got a connection from 127.0.0.1, port: 59152
before loop
java.net.SocketException: socket closed: Bad file number
waiting for connection on port 43210

--------------------

remus% java Put note.txt
connecting to localhost on 43210
16
777
16
761
java.io.IOException: Broken pipe
remus%
0
 

Author Comment

by:MarvynDT
ID: 8031358
objects, would it even matter considering the scope of both objects? Regardless, tried it and still no go...
0
 

Author Comment

by:MarvynDT
ID: 8031371
functionpointer, as stated in the guidelines by my professor, I cannot assume that the data transferred is ASCII or contains any delimiters. That made me decide to stay away from BufferedReader as I have no idea what the server may have to read. Or is my understanding of BufferedReader incorrect?
0
 
LVL 92

Expert Comment

by:objects
ID: 8031396
> would it even matter considering the scope of both objects?

Yes. Closing the stream will close the underlying socket.
Scope has nothing to do with it.

> Regardless, tried it and still no go...

Whats the error now?
Check you aren't prematurely closing the socket elsewhere.

> Or is my understanding of BufferedReader incorrect?

No you aren't. It is for reading text data.


0
 
LVL 92

Expert Comment

by:objects
ID: 8031407
did you remove the close() call from both sendMessage() methods.
0
 

Author Comment

by:MarvynDT
ID: 8031423
Yes, I commented out the close instructions from both sendMessage() methods. I am still producing the same errors.
0
 
LVL 92

Accepted Solution

by:
objects earned 400 total points
ID: 8031447
> I am still producing the same errors.

Are you sure. (Did u restart the server).
I run it here and it basically works.
Though there's a slight problem shutting down the connection but the file gets transferred ok.
0
 
LVL 2

Expert Comment

by:functionpointer
ID: 8031460
your retrievefile method in the code you posted is still doing some funky writing.
0
 
LVL 92

Expert Comment

by:objects
ID: 8031467
and if u close the output stream on the client after the file is sent it all works fine.
0
 
LVL 92

Expert Comment

by:objects
ID: 8031489
> your retrievefile method in the code you posted is still doing some funky writing.

That method never gets called.
0
 

Author Comment

by:MarvynDT
ID: 8031520
I just tried it again and it works. VERY WEIRD, since I had to stop the server program everytime to recompile it. Well whatever...

Thank you objects & functionpointer
0
 

Author Comment

by:MarvynDT
ID: 8031526
I'm not sure which comment from objects to accept as an answer, considering that there were quite a few fixes to the program and the one that solved it all was just executing the code again. So I'll accept that particular comment as the answer.

Although the solution to my particular problem may have been shuttind down the socket prematurely or writing nulls to the file. (In case anybody with similar problems is reading this)
0
 

Author Comment

by:MarvynDT
ID: 8031530
Thanks for sticking around to see this through.
0
 
LVL 92

Expert Comment

by:objects
ID: 8031531
> I just tried it again and it works.

woo hoo :-)
0
 
LVL 92

Expert Comment

by:objects
ID: 8031536
> Thanks for sticking around to see this through.

No worries, thanks for the points :)
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

After being asked a question last year, I went into one of my moods where I did some research and code just for the fun and learning of it all.  Subsequently, from this journey, I put together this article on "Range Searching Using Visual Basic.NET …
This was posted to the Netbeans forum a Feb, 2010 and I also sent it to Verisign. Who didn't help much in my struggles to get my application signed. ------------------------- Start The idea here is to target your cell phones with the correct…
Viewers will learn about arithmetic and Boolean expressions in Java and the logical operators used to create Boolean expressions. We will cover the symbols used for arithmetic expressions and define each logical operator and how to use them in Boole…
This tutorial covers a practical example of lazy loading technique and early loading technique in a Singleton Design Pattern.
Suggested Courses
Course of the Month9 days, 15 hours left to enroll

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question