0

I have written a client-socket "system" that is supposed to upload a file. Although, when I attempt to upload, content duplicates. I'm pretty sure that it is because the program doesn't recognise the eof. I've found something like "Object stream", but I don't fancy importing new classes. I reckon that I don't really require that. But I wanna know how what the problem precisely is and how to hanle it.

package client;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;

public class Client {

    private Socket socket;
    private DataInputStream in;
    private DataOutputStream out;

    public static void main(String[] args) {
        new Client();

    }
    public Client()
    {
        try {
            socket = new Socket("127.0.0.1", 5010);
        
            in = new DataInputStream(socket.getInputStream());
            out = new DataOutputStream(socket.getOutputStream());
            
            this.sendFile("./some.txt");
            
            in.close();
            out.close();
            socket.close();
        }
        catch(UnknownHostException ex)
        {
            System.out.println("unknown host");
        }
        catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    private void sendFile(String path)
    {
        int bytes = 0;
        File file = new File(path);
        FileInputStream input;
        try {
            input = new FileInputStream(file);
            
            long size = file.length();
            //long size = file.getTotalSpace();
            System.out.println(size);
            // send a file's size
            out.writeLong(size);
            byte[] buffer = new byte[1024];
            int i = 0, r=0;
            //while((bytes = input.read(buffer,0,buffer.length))!=-1)
            while(size > 0 && (bytes = input.read(buffer,0,(int)Math.min(buffer.length, size)))!=-1)
            {
                System.out.println("\n -------------"+(++i));
                for (byte b : buffer)
                    try
                    {
                        if ((char)b == '\n' || r == 0)
                            System.out.print("\n" + (++r));
                        System.out.print((char)b);
                        
                    }
                    catch(NullPointerException ex)
                    {
                        
                    }
                out.write(buffer, 0, bytes);
                out.flush();
                size -= bytes;
            }
            
            input.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }
}

package server;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {

    private ServerSocket ss;
    private Socket cs;
    private DataInputStream in;
    private DataOutputStream out;
    public static void main(String[] args) {
        
        new Server();
    }
    public Server()
    {
        try {
            ss = new ServerSocket(5010);
            cs = ss.accept(); 
            
            in = new DataInputStream(cs.getInputStream());
            out = new DataOutputStream(cs.getOutputStream());
            
            this.receiveFile("./uploaded.txt");
            
            in.close();
            out.close();
            cs.close();
            ss.close();
        } 
        catch (IOException e) {
            e.printStackTrace();
        }
    }
    private void receiveFile(String path)
    {
        int bytes = 0;
        try {
            File file = new File(path);
            file.createNewFile();
            FileOutputStream output = new FileOutputStream(file);
            
            long size = in.readLong();
            byte[] buffer = new byte[1024];
            
            int i = 0;
            
            while(size>0 && (bytes = in.read(buffer, 0, (int)Math.min(buffer.length, size))) != -1)
            {
                System.out.println("\n -------------"+(++i));
                for (byte b : buffer)
                    try
                    {
                        System.out.print((char)b);
                    }
                    catch(NullPointerException ex)
                    {
                        
                    }
                output.write(buffer, 0, bytes);
                size -= bytes;
                
            }
            
            output.close();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

  • [Java sending and receiving file (byte) over sockets](https://stackoverflow.com/questions/9520911/java-sending-and-receiving-file-byte-over-sockets) – Abra Feb 07 '23 at 05:45
  • [Java sending and receiving file over sockets](https://stackoverflow.com/questions/38732970/java-sending-and-receiving-file-over-sockets) – Abra Feb 07 '23 at 05:52
  • the variable `bytes` tells you how many bytes were received. If 5 bytes were received then your program prints 1024 bytes anyway. What do you suppose goes in the extra 1019 bytes that it prints? – user253751 Feb 07 '23 at 10:11

2 Answers2

0

The problem was that I didn't check if the size were 0 on the client side.

-1

That try catch should NOT be in the for loop !!!! It only needs single code use by wrapping. Also use counting metering conventionally the number of bytes with a conventional numeric "for" loop, Not for(byte b : buffer). Note: byte is not strictly numeric, it will only reach to 255 in the for counter! It depends the quantity bytes required iterated over and should be as many as are packaged to it over the connection.

In the read you need to obtain the number of bytes sent andmark that into the write length to take from the array, so it would be better to instantiate the array based on the number of bytes or maximum bytes the the client sender has sent or negotiated as the maximum allowed (see the api docs for the stream. NB ObjectStream does not apply , it's for RMI)

Of counting into the byte[] buffer array, you should remove it from the method and put it as a global. In the method , instantiate a new "buffer" array on the global variable each iteration of the loop according to the number of bytes read as it's new length.

The code does not appear to be particularly safe or debugable. You might try carefully constructing it starting again from scratch.

Samuel Marchant
  • 331
  • 2
  • 6
  • 1
    The for loop should work. An array is an enumerable, you can read up on that here: https://www.w3schools.com/java/java_arrays_loop.asp. – SupaMaggie70 b Feb 07 '23 at 14:35
  • 1
    I meant iterator, which you can read up on here: https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html – SupaMaggie70 b Feb 07 '23 at 14:36
  • Incidentally if ((char)b == '\n' || r == 0) any Unix new line is "2 bytes of size , and a windows new line is 4 bytes of size, so you must create a string from the bytes 2 or four to check NOT SIMPLY ONE byte. see new String constructor in the API docs. – Samuel Marchant Feb 08 '23 at 15:35
  • Thanks about the Array iterator, i always use counting with them particularly in that situation (it checksums), The exception should be outside the loop, it only needs setting on the code once. – Samuel Marchant Feb 08 '23 at 15:36
  • Yeah, you should consider deleting your answer as it is incorrect and misleading. – SupaMaggie70 b Feb 08 '23 at 15:44
  • Unix newline is \r\n, which as you may notice includes \n. You can trim the \r from the end, however, this only matters if you are reading from a file written by a unix program and not your own program, as most unix programs will recognize simply \n as a newline. – SupaMaggie70 b Feb 08 '23 at 15:45
  • The counting is too incoherent from the server-socket AND THAT is why i use numeric for() loop counting not collection iteration !!! particularly with bytes !!! while(size>0 && (bytes = in.read(buffer, 0, (int)Math.min(buffer.length, size))) != -1) , the variable "size" i believe is an attempted File-Size pre-transmission for the server , and you are not measuring byte-packet-size sent as i said in the answer , and you are not marking the reception size into the array in the server coherently either. Basically user253751 was saying similar. – Samuel Marchant Feb 08 '23 at 15:57
  • And when you come to write, the number of bytes each loop iteration will not necessarily ever be 1024, you should only be writing the bytes recieved in the iteration, "so count and mark the quantities properly" . – Samuel Marchant Feb 08 '23 at 16:04
  • SupaMaggie70 b you should consider learning newline chars ... private static final char[] carr_ret_line = {'\r', '\n'}; // CRLF private final String[] http1011CacheHeaderParts = { ((String) new Character('\r').toString()), ((String) new Character('\n').toString()), ((String) new String(carr_ret_line)), – Samuel Marchant Feb 08 '23 at 16:09
  • Your answer is your opinion on how things should be done. It does not answer the original question and is misleading. Newline characters have nothing to do with the question; if you control the input and output it does not matter what newline the os prefers. The only time it will is when you are reading from the system. Newlines are not mentioned in the original question nor your answer. The \n actually stands for new line where \r sends it to the front of the line. The reason unix includes both goes back to typewriters, but including just \n always creates a new line. – SupaMaggie70 b Feb 08 '23 at 16:35