java.net.SocketException: redefinição de conexão

128

Estou recebendo o seguinte erro ao tentar ler de um soquete. Estou fazendo readInt()isso InputStreame estou recebendo esse erro. Examinando a documentação, isso sugere que a parte da conexão do cliente fechou a conexão. Nesse cenário, eu sou o servidor.

Eu tenho acesso aos arquivos de log do cliente e ele não está fechando a conexão e, de fato, seus arquivos de log sugerem que eu estou fechando a conexão. Então, alguém tem uma idéia de por que isso está acontecendo? O que mais deve ser verificado? Isso ocorre quando existem recursos locais que talvez estejam atingindo limites?


Percebo que tenho a seguinte linha:

socket.setSoTimeout(10000);

pouco antes da readInt(). Há uma razão para isso (longa história), mas apenas curioso, existem circunstâncias em que isso pode levar ao erro indicado? Eu tenho o servidor em execução no meu IDE e, por acaso, o deixei preso em um ponto de interrupção e, em seguida, notei que exatamente os mesmos erros começaram a aparecer em meus próprios logs no meu IDE.

De qualquer forma, apenas mencionando, espero que não seja um arenque vermelho. :-(

azulado
fonte
Você tem rastreamentos de pilha de ambos os lados? Você pode descrever a arquitetura de rede um pouco mais? (Na Internet selvagem? Na mesma máquina? Em algum lugar no meio?) Isso acontece o tempo todo? Ou intermitentemente?
Stu Thompson

Respostas:

116

Existem várias causas possíveis.

  1. A outra extremidade deliberadamente redefiniu a conexão, de uma maneira que não documentarei aqui. É raro e geralmente incorreto o software aplicativo fazer isso, mas não é desconhecido o software comercial.

  2. Mais comumente, é causado pela gravação em uma conexão que a outra extremidade já foi fechada normalmente. Em outras palavras, um erro no protocolo do aplicativo.

  3. Também pode ser causado pelo fechamento de um soquete quando houver dados não lidos no buffer de recebimento do soquete.

  4. No Windows, o 'software causou a interrupção da conexão', que não é o mesmo que 'redefinição da conexão', é causado por problemas de rede ao enviar do seu lado. Há um artigo da base de conhecimento da Microsoft sobre isso.

Marquês de Lorne
fonte
@MattLyons Thanks. Existem artigos muito melhores do MSDN que isso. Francamente, acho difícil acreditar nisso. Uma conexão nem existirá até que os endereços IP de origem e destino corretos tenham sido estabelecidos. Os artigos do MSDN que eu vi referem-se a erros de rede persistentes que atingem o tempo limite da conexão.
Marquês de Lorne
48

A redefinição da conexão significa simplesmente que um TCP RST foi recebido. Isso acontece quando seu colega recebe dados que não podem ser processados ​​e pode haver várias razões para isso.

O mais simples é quando você fecha o soquete e, em seguida, grava mais dados no fluxo de saída. Ao fechar o soquete, você disse ao seu colega que havia terminado de falar e ele pode esquecer sua conexão. De qualquer maneira, quando você envia mais dados nesse fluxo, o ponto a rejeita com um RST para que você saiba que não está ouvindo.

Em outros casos, um firewall intermediário ou até o próprio host remoto pode "esquecer" sua conexão TCP. Isso pode acontecer se você não enviar dados por um longo período de tempo (2 horas é um tempo limite comum) ou porque o par foi reiniciado e perdeu suas informações sobre conexões ativas. O envio de dados em uma dessas conexões desativadas também causará um RST.


Atualização em resposta a informações adicionais:

Dê uma olhada no seu manuseio do SocketTimeoutException. Essa exceção é gerada se o tempo limite configurado for excedido enquanto bloqueado em uma operação de soquete. O estado do soquete em si não é alterado quando essa exceção é lançada, mas se o manipulador de exceções fechar o soquete e tentar gravar nele, você estará em uma condição de redefinição de conexão. setSoTimeout()destina-se a fornecer uma maneira limpa de interromper uma read()operação que poderia bloquear para sempre, sem fazer coisas sujas, como fechar o soquete de outro encadeamento.

erickson
fonte
Não está correto em vários aspectos. A coleta de lixo e as saídas do processo causam fechamentos adequados, não redefinições, mas um fechamento seguido de uma gravação pelo par pode induzir uma redefinição em vez de um EOS. SocketTimeoutExceptions são geradas apenas se o leitor tiver definido um tempo limite de leitura.
Marquês de Lorne
E nem sempre significa que um RST foi recebido. Também pode significar que um foi gerado por esse lado.
Marquês de Lorne
17

Sempre que tive problemas estranhos como esse, costumo me sentar com uma ferramenta como o WireShark e ver os dados brutos sendo transmitidos para frente e para trás. Você pode se surpreender onde as coisas estão sendo desconectadas e só será notificado quando tentar ler.

GEOCHET
fonte
9

Vergonhoso dizer isso, mas quando tive esse problema, foi simplesmente um erro que eu estava fechando a conexão antes de ler todos os dados. Nos casos em que pequenas seqüências de caracteres foram retornadas, funcionou, mas isso provavelmente ocorreu porque toda a resposta foi armazenada em buffer antes de eu a fechar.

Nos casos em que quantidades maiores de texto são retornadas, a exceção foi lançada, pois mais do que um buffer estava retornando.

Você pode verificar essa supervisão. Lembre-se de abrir um URL é como um arquivo, feche-o (libere a conexão) depois que ele for totalmente lido.

Scott S
fonte
9

Você deve inspecionar o rastreamento completo com muito cuidado,

Eu tenho um aplicativo de soquete de servidor e corrigi um java.net.SocketException: Connection resetcaso.

No meu caso, isso acontece durante a leitura de um Socketobjeto clientSocket que está fechado sua conexão por algum motivo. (Rede perdida, falha no firewall ou no aplicativo ou fechamento pretendido)

Na verdade, eu estava restabelecendo a conexão quando recebi um erro ao ler este objeto Socket.

Socket clientSocket = ServerSocket.accept();
is = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
int readed = is.read(); // WHERE ERROR STARTS !!!

O interessante é que, for my JAVA Socketse um cliente se conectar ao meu ServerSockete fechar sua conexão sem enviar nada, is.read()chama-se recursivamente. Parece que, por estar em um loop while infinito para ler a partir desse soquete, você tenta ler a partir de uma conexão fechada. Se você usar algo como abaixo para operação de leitura;

while(true)
{
  Receive();
}

Então você obtém um stackTrace algo como abaixo

java.net.SocketException: Socket is closed
    at java.net.ServerSocket.accept(ServerSocket.java:494)

O que fiz foi fechar o ServerSocket e renovar minha conexão, aguardando novas conexões de clientes.

String Receive() throws Exception
{
try {                   
            int readed = is.read();
           ....
}catch(Exception e)
{
        tryReConnect();
        logit(); //etc
}


//...
}

Isso restabelece minha conexão para soquete de cliente desconhecido perde

private void tryReConnect()
        {
            try
            {
                ServerSocket.close();
                //empty my old lost connection and let it get by garbage col. immediately 
                clientSocket=null;
                System.gc();
                //Wait a new client Socket connection and address this to my local variable
                clientSocket= ServerSocket.accept(); // Waiting for another Connection
                System.out.println("Connection established...");
            }catch (Exception e) {
                String message="ReConnect not successful "+e.getMessage();
                logit();//etc...
            }
        }

Não consegui encontrar outra maneira porque, como você vê na imagem abaixo, não consegue entender se a conexão está perdida ou não sem a try and catch, porque tudo parece certo. Obtive este instantâneo enquanto estava obtendo Connection resetcontinuamente.

insira a descrição da imagem aqui

Davut Gürbüz
fonte
6

Eu tive o mesmo erro. Encontrei a solução para o problema agora. O problema era que o programa cliente estava sendo concluído antes do servidor ler os fluxos.

kml_ckr
fonte
Isso não causaria essa exceção por si só.
Marquês de Lorne
seria se System.exit (0) mata o programa e ninguém chama socket.close () porque a conexão está em um estado ruim e não foi fechada corretamente. sooo disse mais apropriadamente que ele tinha um programa cliente que fecha sem fechar soquetes;) o que é uma coisa ruim e deve ser corrigida.
Dean Hiller
1
@ DeanHiller Não, não. O sistema operacional fecharia o soquete da mesma maneira que o aplicativo deveria.
Marquês de Lorne
@EJP .... Não tenho certeza ... Só sei que poderíamos reproduzi-lo com o System.exit, mas não me lembro do OS / config, como era há algum tempo atrás ... chamando socket.close ( ) no servidor impediu a redefinição da conexão e se comportou de maneira mais adequada.
precisa
2
@DeanHiller O processo de leitura saiu antes que o processo de gravação tivesse terminado.
Marquês de Lorne
4

Eu tive esse problema com um sistema SOA escrito em Java. Eu estava executando o cliente e o servidor em máquinas físicas diferentes e eles funcionaram bem por um longo período de tempo. Em seguida, essas redefinições de conexão desagradáveis ​​apareceram no log do cliente e não havia nada de estranho no log do servidor. Reiniciar o cliente e o servidor não resolveu o problema. Finalmente, descobrimos que o heap no lado do servidor estava cheio e aumentamos a memória disponível para a JVM: problema resolvido! Observe que não havia OutOfMemoryError no log: a memória era escassa, não esgotada.

Pino
fonte
2

Verifique a versão Java do seu servidor. Aconteceu comigo porque meu Weblogic 10.3.6 estava no JDK 1.7.0_75, no TLSv1. O ponto final restante que eu estava tentando consumir estava desligando qualquer coisa abaixo do TLSv1.2.

Por padrão, o Weblogic estava tentando negociar o protocolo compartilhado mais forte. Veja detalhes aqui: Problemas com a configuração da propriedade do sistema https.protocols para conexões HTTPS .

Adicionei log SSL detalhado para identificar o TLS suportado. Isso indicava que o TLSv1 estava sendo usado para o aperto de mão.
-Djavax.net.debug=ssl:handshake:verbose:keymanager:trustmanager -Djava.security.debug=access:stack

Eu resolvi isso enviando o recurso para o nosso produto compatível com JDK8, o JDK8 padrão é TLSv1.2. Para aqueles restritos ao JDK7, também testei com êxito uma solução alternativa para o Java 7 atualizando para o TLSv1.2. Eu usei esta resposta: Como habilitar o TLS 1.2 no Java 7

Sumiya
fonte
muito obrigado, você me mostra uma nova direção para corrigir meu problema. e finalmente achei que é o caso !!!
karl li
1

Eu também tive esse problema com um programa Java tentando enviar um comando em um servidor via SSH. O problema estava com a máquina executando o código Java. Não tinha permissão para se conectar ao servidor remoto. O método write () estava funcionando bem, mas o método read () estava lançando um java.net.SocketException: Redefinição de conexão. Corrigi esse problema adicionando a chave SSH do cliente às chaves conhecidas do servidor remoto.

pmartin8
fonte
0

Na minha experiência, frequentemente encontro as seguintes situações;

  1. Se você trabalha em uma empresa corporativa, entre em contato com a equipe de rede e segurança. Como em solicitações feitas a serviços externos, pode ser necessário conceder permissão para o terminal relevante.

  2. Outro problema é que o certificado SSL pode ter expirado no servidor em que seu aplicativo está sendo executado.

bmck
fonte