Problema transmissão de arquivo pelo socket em java

Olá a todos
Eu estou com um problema na leitura de arquivos via socket.
Abaixo eu coloquei o método que eu criei para enviar e receber arquivos.
O que acontece é que eu consigo enviar todos os bytes do arquivo, porem a recepção não está conseguindo lê-lo completamente. Ele as vezes lê menos do que foi enviado ou não lê nada.
Eu coloquei o print para obter essas conclusões, a saída do enviarArquivo é sempre algo assim:

0 - lidos: 4096
1 - lidos: 4096
2 - lidos: 4096
3 - lidos: 4096
4 - lidos: 4096
5 - lidos: 4096
6 - lidos: 4096
7 - lidos: 4096
8 - lidos: 4096
9 - lidos: 4096
10 - lidos: 4096
11 - lidos: 4096
12 - lidos: 4096
13 - lidos: 4096
14 - lidos: 4096
15 - lidos: 4096
16 - lidos: 4096
17 - lidos: 4096
18 - lidos: 4096
19 - lidos: 4096
20 - lidos: 4096
21 - lidos: 4096
22 - lidos: 4096
23 - lidos: 4096
24 - lidos: 4096
25 - lidos: 4096
26 - lidos: 4096
27 - lidos: 4096
28 - lidos: 4096
29 - lidos: 4096
30 - lidos: 4096
31 - lidos: 4096
32 - lidos: 4096
33 - lidos: 4096
34 - lidos: 4096
35 - lidos: 4096
36 - lidos: 4096
37 - lidos: 4096
38 - lidos: 4096
39 - lidos: 4096
40 - lidos: 4096
41 - lidos: 4096
42 - lidos: 4096
43 - lidos: 4096
44 - lidos: 4096
45 - lidos: 4096
46 - lidos: 4096
47 - lidos: 4096
48 - lidos: 4096
49 - lidos: 4096
50 - lidos: 4096
51 - lidos: 3698

//arquivo enviado

A saída do receberArquivo já é assim:

0 - lidos: 4096
1 - lidos: 4096
2 - lidos: 4096
3 - lidos: 4096
4 - lidos: 4096
5 - lidos: 4096
6 - lidos: 4096
7 - lidos: 4096
8 - lidos: 4096
9 - lidos: 4096
10 - lidos: 4096
11 - lidos: 4096
12 - lidos: 4096
13 - lidos: 4096
14 - lidos: 4096
15 - lidos: 4096
16 - lidos: 4096
17 - lidos: 4096
18 - lidos: 4096
19 - lidos: 4096
20 - lidos: 4096
21 - lidos: 4096
22 - lidos: 4096
23 - lidos: 4096
24 - lidos: 4096
25 - lidos: 4096
26 - lidos: 4096
27 - lidos: 4096
28 - lidos: 4096
29 - lidos: 4096
30 - lidos: 4096
31 - lidos: 4096
32 - lidos: 4096
33 - lidos: 4096
34 - lidos: 4096
35 - lidos: 4096
36 - lidos: 34
37 - lidos: 4096
38 - lidos: 4096
39 - lidos: 4096
40 - lidos: 4096
41 - lidos: 4096
42 - lidos: 4096
43 - lidos: 4096
44 - lidos: 4096
45 - lidos: 4096
46 - lidos: 4096
47 - lidos: 4096
48 - lidos: 4096
49 - lidos: 4096
50 - lidos: 4096

O arquivo que enviei tem tamanho de 212594.

Uma outra coisa interessante que não entendo é que quando eu fecho a conexão com o servidor(o que está enviando) da erro de IndexOutOfBoundsException.

Então alguém sabe me dizer o que der errado no método?

public void enviarArquivo(String caminho) throws IOException {
        
            File file = new File(caminho);
            FileInputStream fileIn = new FileInputStream(file);

            OutputStream out = cliente.getOutputStream();
        
            int tam = 4096;
            byte[] buffer = new byte[tam];
            int lidos = 0;
            long tamTotal = file.length();
            long tamParcial = 0;
            
            saida.println(tamTotal);
            
            int i = 0;
            
            while(tamParcial < tamTotal){
                
                lidos = fileIn.read(buffer, 0, tam);
                
                tamParcial = tamParcial + lidos;
                
                out.write(buffer, 0, lidos);
            
                System.out.println(i++ + " - lidos: "+lidos);    
                
            }
            
            out.flush();
            
            fileIn.close();
            
            System.out.println("arquivo enviado");
            
        }`


public void receberArquivo(String caminho) throws IOException {
            
        FileOutputStream fos = new FileOutputStream(caminho);
        
        int tam = 4096;
        byte[] buffer = new byte[tam];
        int lidos = 0;
        
        InputStream in = cliente.getInputStream();
        
        long tamTotal =  entrada.nextLong();
        
        long tamParcial = 0;
        
        int i = 0;
        
        while (tamParcial < tamTotal) {
            
            lidos = in.read(buffer, 0, tam);
            
            
            tamParcial = tamParcial + lidos;
             
            
            fos.write(buffer, 0, lidos);
        
            
            System.out.println(i++ + " - lidos: "+lidos);
                
        }
        
        fos.flush();
        fos.close();
        
        System.out.println("arquivo recebido");
            
        
    }

Cola a stack trace do erro

Aqui está o stack trace:
ThreadUsuario é a minha classe que torna meu servidor multi usuario.

Exception in thread “Thread-0” java.lang.IndexOutOfBoundsException
at java.io.FileOutputStream.writeBytes(Native Method)
at java.io.FileOutputStream.write(FileOutputStream.java:326)
at model.ThreadUsuario.receberArquivo(ThreadUsuario.java:190)
at model.ThreadUsuario.run(ThreadUsuario.java:94)
at java.lang.Thread.run(Thread.java:745)

não é obvio ? tu declarou um tamanho 4096 e está tentando alocar 212594… se o problema é o inglês é só por no google: “index out of bounds” é “Índice fora dos limites”

não é obvio ? tu declarou um tamanho 4096 e está tentando alocar
212594… se o problema é o inglês é só por no google: “index out of
bounds” é “Índice fora dos limites”

não, eu estou passando um grande arquivo pouco a pouco, ele tem 212594, porém eu leio apenas 4096 e envio até acabar o arquivo. Depois que o programa diz que enviou tudo, ao fechar ele que da esse erro. Eu acho que é como se tivesse coisa para enviar e ele só libera ao fechar a conexão.

Coloque o seguinte teste dentro do seu loop:

if(lidos > 0){
    fos.write(buffer, 0, lidos);
}

o método read() pode retornar 0 ou -1 quando ele atinge o final da entrada que está sendo lida.

Eu me atrapalhei um pouco aqui para responder no guj.kk

Pelo que eu entendi, você quer que eu coloque um if dentro do método de enviar os dados para o arquivo. Dessa forma o while do método de receberArquivo ficou assim:

while (tamParcial < tamTotal) {
            
            lidos = in.read(buffer, 0, tam);
            
            
            tamParcial = tamParcial + lidos;
             
            if(lidos > 0){
                fos.write(buffer, 0, lidos);
            }
            
        
            
            System.out.println(i++ + " - lidos: "+lidos);
                
        }

E infelizmente não deu certo, porém a saida mudou. Ao invez de :
48 - lidos: 4096
49 - lidos: 4096
50 - lidos: 4096

A saida do receber Arquivo foi:

    48 - lidos: 4096
    49 - lidos: 4096
    50 - lidos: 3698

Além disso quando fecho o envio não da mais erro, ao invéz sai -1 sem parar, dessa forma:

    51 - lidos: -1
    52 - lidos: -1
    53 - lidos: -1 
    ....

Na verdade, fica mais interessante fazer esse loop assim:

lidos = fileIn.read(buffer, 0, tam);
while (lidos > 0) {
        out.write(buffer, 0, lidos);
        System.out.println(i++ + " - lidos: "+lidos);
        lidos = fileIn.read(buffer, 0, tam);
}