0

I'm new to Java. I need to send over socket the file content, together with a double number. My idea is to wrap these two fields into a custom object. Since object File is not serializable, how to send/recv this custom object? Thanks in advance. PS: The sending party will decide if it needs to send the file according to the value of the "double" number. For example:

class MyObject{
    double number;
    File file;
}

When sending, the logic is something like this:

MyObject my = new MyObject();

if(my.number > 0){
    my.file = open_file(aaa.jpg);
}else{
    //Not opening any file
}

send(my);
wei
  • 213
  • 4
  • 13
  • 2
    The `File` object in java represents the _path_ of a file, **not** its content. You would need to send the contents of a `FileInputStream` over your socket. – Boris the Spider Mar 24 '13 at 15:45
  • firstly, thanks for your attention. Yes. I know. It's just pseudo code. The idea of the logic is that I don't need to send the file every time. It depends on the value of the number. – wei Mar 24 '13 at 18:41

1 Answers1

-1

Here is a quick example application that sends data to itself over Sockets.

public class App {

    private static final AtomicInteger port = new AtomicInteger(-1);
    private static final AtomicBoolean read = new AtomicBoolean(true);

    private static final class SocketReader implements Runnable {

        @Override
        public void run() {
            try {
                final ServerSocket serverSocket = new ServerSocket(0);
                System.out.println("Connected on " + serverSocket);
                synchronized (port) {
                    port.set(serverSocket.getLocalPort());
                    port.notifyAll();
                }
                while (read.get()) {
                    try (final Socket socket = serverSocket.accept()) {
                        final DataInputStream dis = new DataInputStream(socket.getInputStream());
                        System.out.println(dis.readDouble());                        
                        byte[] buffer = new byte[1024];
                        int numRead;
                        while ((numRead = dis.read(buffer)) != -1) {
                            System.out.print(new String(buffer, 0, numRead, "UTF-8"));
                        }
                    }

                }
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }

        }
    }

    private static final class SocketWriter implements Runnable {

        private final double d;
        private final File file;

        public SocketWriter(double d, File file) {
            this.d = d;
            this.file = file;
        }

        @Override
        public void run() {
            try {
                while (port.get() < 1) {
                    synchronized (port) {
                        port.wait();
                    }
                }
                try (final Socket clientSocket = new Socket("localhost", port.get());
                        final DataOutputStream dos = new DataOutputStream(clientSocket.getOutputStream())) {
                    System.out.println(clientSocket);
                    dos.writeDouble(d);
                    try (final FileInputStream fis = new FileInputStream(file)) {
                        byte[] buffer = new byte[1024];
                        int bytesRead;
                        while ((bytesRead = fis.read(buffer)) != -1) {
                            dos.write(buffer, 0, bytesRead);
                        }
                    }
                    dos.flush();
                }
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        final double d = 2.35;
        final File f = new File(new File(System.getProperty("user.home"), "Downloads"), "readme.txt");
        final ExecutorService executorService = Executors.newSingleThreadExecutor();
        final Future<?> future = executorService.submit(new SocketReader());
        new SocketWriter(d, f).run();
        read.set(false);
        executorService.shutdownNow();
        try {
            future.get();
        } catch (ExecutionException ex) {
            throw new RuntimeException(ex);
        }
    }
}

First we send the double serialised, then it sends the contents of a random file in my Downloads directory.

Another Thread, meanwhile, echos all that to the console.

Boris the Spider
  • 59,842
  • 6
  • 106
  • 166
  • thanks. I also know it's possible to send the two fields like this way. But the point is how to wrap it into an custom object. – wei Mar 24 '13 at 17:54
  • You can always read your `File` into a `String` or `byte[]` and send it - that would require holding the whole file in memory however - a little expensive. From your comment - the reader can close the stream if it doesn't want the `File`... – Boris the Spider Mar 24 '13 at 19:32
  • Hi. I ran your code. It worked when the file is readme.txt. When I replace it with a.jpg, it didn't work. The reader was blocked in `line = bufferedReader.readLine()`. Could you please tell me how to solve it? – wei Mar 24 '13 at 20:05
  • This code does not work. It uses both an ObjectInputStream and a BufferedReader on the same socket. Both these buffer, and they will both steal data from each other. Untested guesswork. -1 – user207421 Mar 24 '13 at 21:28
  • @EJP this is untrue. Check the source code for `ObjectInputStream`. The `readDouble` method reads the stream header then exactly 8 bytes in order the read the `double`. – Boris the Spider Mar 24 '13 at 22:00
  • @EJP further, [this](http://stackoverflow.com/questions/3365261/does-a-buffered-objectinputstream-exist) SO post suggests that `ObjectInputStream` is not buffered in any case. – Boris the Spider Mar 24 '13 at 23:35
  • @bmorris (1) `ObjectInputStream` uses a 1k buffer, at least part of the time, including `readDouble()`. The answer you cited doesn't appear to know that. (2) `BufferedReader` uses a buffer of 4k `chars`, all the time. There's no actual reason to use `ObjectInput/OutputStream` here at all: `DataInput/OutputStream` would work much better. It is also *incorrect* to use a `BufferedReader` as the input is being written as bytes by the peer. It should be an `InputStream`, preferably the same `DataInputStream` that was used to write the `double.` – user207421 Mar 25 '13 at 04:35
  • @EJP I have changed the example as you suggest - using `DataInput/OutputStream`. – Boris the Spider Mar 25 '13 at 08:34