java.net.SocketException : 연결 재설정


128

소켓에서 읽으려고하면 다음 오류가 발생합니다. 내가하고있어 readInt()이에 InputStream, 나는이 오류를 얻고있다. 문서를 숙독하면 연결의 클라이언트 부분이 연결을 닫았 음을 알 수 있습니다. 이 시나리오에서 나는 서버입니다.

클라이언트 로그 파일에 액세스 할 수 있지만 연결이 닫히지 않고 실제로 로그 파일에 연결을 닫고 있다고 제안됩니다. 왜 이런 일이 일어나는지 아는 사람이 있습니까? 또 무엇을 확인해야합니까? 임계 값에 도달 한 로컬 리소스가있을 때 발생합니까?


다음 줄이 있습니다.

socket.setSoTimeout(10000);

받는 사람 직전 readInt(). 이에 대한 이유 (긴 이야기)가 있지만 궁금한 점이 있습니다. 이로 인해 표시된 오류가 발생할 수있는 상황이 있습니까? IDE에서 서버를 실행하고 있는데, IDE를 중단 점에 멈춰 놓은 후 IDE의 내 로그에 똑같은 오류가 나타나기 시작하는 것을 발견했습니다.

어쨌든, 그것을 언급하기 만하면 붉은 청어가 아니길 바랍니다. :-(


양쪽에서 스택 트레이스가 있습니까? 네트워크 아키텍처에 대해 좀 더 설명해 주시겠습니까? (와일드 인터넷을 통해? 같은 컴퓨터에서? 그 사이 어딘가?) 항상 발생합니까? 아니면 간헐적으로?
Stu Thompson

답변:


116

몇 가지 가능한 원인이 있습니다.

  1. 다른 쪽 끝은 여기에 문서화하지 않을 방식으로 의도적으로 연결을 재설정했습니다. 응용 프로그램 소프트웨어가이 작업을 수행하는 것은 드물고 일반적으로 올바르지 않지만 상용 소프트웨어에 대해서는 알려지지 않았습니다.

  2. 더 일반적으로 다른 쪽 끝이 이미 정상적으로 닫힌 연결에 쓰기 때문에 발생합니다. 즉, 응용 프로그램 프로토콜 오류입니다.

  3. 소켓 수신 버퍼에 읽지 않은 데이터가있을 때 소켓을 닫으면 발생할 수도 있습니다.

  4. Windows에서 '연결 재설정'과 다른 '소프트웨어로 인한 연결 중단'은 사용자 쪽에서 보내는 네트워크 문제로 인해 발생합니다. 이에 대한 Microsoft 기술 자료 문서가 있습니다.


@MattLyons 감사합니다. 그것보다 훨씬 더 나은 MSDN 기사가 있습니다. 솔직히 나는 그것을 믿기 어렵다는 것을 안다. 올바른 소스 및 대상 IP 주소가 설정 될 때까지 연결이 존재하지 않습니다. 내가 본 MSDN 기사는 연결 시간이 초과되는 지속적인 네트워크 오류를 참조합니다.
Marquis of Lorne

48

연결 재설정은 단순히 TCP RST가 수신되었음을 의미합니다. 이는 피어가 처리 할 수없는 데이터를 수신 할 때 발생하며 그 이유는 다양 할 수 있습니다.

가장 간단한 방법은 소켓을 닫은 다음 출력 스트림에 더 많은 데이터를 쓰는 것입니다. 소켓을 닫음으로써 당신은 당신이 말을 끝냈 음을 동료에게 알 렸으며 당신의 연결을 잊을 수 있습니다. 어쨌든 해당 스트림에서 더 많은 데이터를 보내면 피어는 RST를 사용하여 데이터를 거부하여 수신 중이 아님을 알립니다.

다른 경우에는 개입 방화벽이나 원격 호스트 자체가 TCP 연결을 "잊을"수 있습니다. 오랜 시간 동안 데이터를 보내지 않거나 (2 시간이 일반적인 제한 시간 임) 피어가 재부팅되어 활성 연결에 대한 정보가 손실 되었기 때문에 발생할 수 있습니다. 이러한 존재하지 않는 연결 중 하나에서 데이터를 전송하면 RST도 발생합니다.


추가 정보에 대한 업데이트 :

의 당신의 처리를 자세히 살펴 보자 SocketTimeoutException. 소켓 작업에서 차단 된 동안 구성된 제한 시간이 초과되면이 예외가 발생합니다. 이 예외가 throw 될 때 소켓 자체의 상태는 변경되지 않지만 예외 처리기가 소켓을 닫은 다음 소켓에 쓰려고하면 연결 재설정 상태가됩니다. 다른 스레드에서 소켓을 닫는 것과 같은 더러운 작업을 수행하지 않고 영원히 차단 될 수 setSoTimeout()있는 read()작업 을 중단 할 수있는 깨끗한 방법을 제공합니다 .


여러 측면에서 정확하지 않습니다. 가비지 수집과 프로세스 종료는 모두 재설정이 아닌 적절한 종료를 유발하지만, 종료 후 피어에 의한 쓰기는 EOS가 아닌 재설정을 유도 할 수 있습니다. SocketTimeoutExceptions는 판독기가 읽기 제한 시간을 설정 한 경우에만 발생합니다.
Marquis of Lorne

그리고 항상 RST를 받았다는 의미는 아닙니다. 그것은 또한 하나가 이쪽에서 생성되었음을 의미 할 수 있습니다.
Marquis of Lorne

17

이와 같은 이상한 문제가있을 때마다 보통 WireShark 와 같은 도구 를 사용하여 앞뒤로 전달되는 원시 데이터를 확인합니다. 어디에서 연결이 끊어 지는지 놀라고 읽으려고 할 때만 알림을 받습니다.


9

부끄럽지만이 문제가 발생했을 때 모든 데이터를 읽기 전에 연결을 끊은 것은 단순히 실수였습니다. 작은 문자열이 반환되는 경우 작동했지만 전체 응답이 버퍼링 되었기 때문일 수 있습니다.

더 많은 양의 텍스트가 반환되는 경우 버퍼가 더 많이 반환되므로 예외가 발생했습니다.

이 감독을 확인할 수 있습니다. URL을 여는 것은 파일과 같다는 것을 기억하십시오. 완전히 읽은 후에는 반드시 닫아야합니다 (연결 해제).


9

전체 추적을 매우 신중하게 검사해야합니다.

서버 소켓 응용 프로그램이 있고 java.net.SocketException: Connection reset케이스를 수정했습니다 .

제 경우에는 Socket어떤 이유로 인해 연결이 닫힌 clientSocket 객체 에서 읽는 동안 발생합니다 . (네트워크 손실, 방화벽 또는 애플리케이션 충돌 또는 의도 된 종료)

실제로이 Socket 객체에서 읽는 동안 오류가 발생하면 연결을 다시 설정했습니다.

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

흥미로운 점은 for my JAVA Socket경우에 클라이언트 커넥트 내 ServerSocket닫고 아무것도 전송하지 않고 그 연결이 is.read()자신을 호출 recursively.It 때문에 무한에 닫힌 연결에서 읽으려고이 소켓에서 읽는 동안 루프가되는 것 같다. 읽기 작업을 위해 아래와 같은 것을 사용하면;

while(true)
{
  Receive();
}

그런 다음 아래와 같이 stackTrace를 얻습니다.

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

내가 한 일은 ServerSocket을 닫고 연결을 갱신하고 추가 수신 클라이언트 연결을 기다리는 것입니다.

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


//...
}

알 수없는 클라이언트 소켓 손실에 대한 연결이 다시 설정됩니다.

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...
            }
        }

아래 이미지에서 볼 수 있듯이 try and catch모든 것이 올바르게 보이기 때문에 연결이 끊어 졌는지 여부를 이해할 수 없기 때문에 다른 방법을 찾을 수 없습니다 . Connection reset계속해서 찍는 동안이 스냅 샷을 얻었습니다 .

여기에 이미지 설명 입력


6

나는 같은 오류가 있었다. 지금 문제에 대한 해결책을 찾았습니다. 문제는 서버가 스트림을 읽기 전에 클라이언트 프로그램이 완료되었다는 것입니다.


그 자체로는이 예외가 발생하지 않습니다.
Marquis of Lorne

System.exit (0)이 프로그램을 종료하고 연결이 잘못된 상태에 있고 제대로 닫히지 않았기 때문에 아무도 socket.close ()를 호출하지 않는 경우입니다. sooo는 소켓을 닫지 않고 종료하는 클라이언트 프로그램이 있다고 더 적절하게 말했습니다.;) 이것은 나쁜 일이며 수정해야합니다.
Dean Hiller 2012

1
@DeanHiller 아니요. 운영 체제는 응용 프로그램과 동일한 방식으로 소켓을 닫습니다.
Marquis of Lorne

@EJP .... 잘 모르겠습니다 ... System.exit로 재현 할 수 있다는 것을 알고 있지만 얼마 전 OS / config를 기억하지 못합니다 .... socket.close ( ) 서버에서 연결 재설정을 방지하고 더 제대로 작동했습니다.
Dean Hiller 2013 년

2
@DeanHiller 쓰기 프로세스가 쓰기를 완료하기 전에 읽기 프로세스가 종료되었습니다.
Marquis of Lorne

4

Java로 작성된 SOA 시스템에서이 문제가 발생했습니다. 나는 클라이언트와 서버를 서로 다른 물리적 컴퓨터에서 실행하고 있었고 오랫동안 잘 작동했으며 클라이언트 로그에 이러한 불쾌한 연결 재설정이 나타 났고 서버 로그에는 이상한 것이 없었습니다. 클라이언트와 서버를 모두 다시 시작해도 문제가 해결되지 않았습니다. 마지막으로 서버 측의 힙이 가득 차서 JVM에서 사용할 수있는 메모리를 늘 렸습니다. 문제가 해결되었습니다! 로그에는 OutOfMemoryError가 없었습니다. 메모리는 고갈되지 않고 부족했습니다.


2

서버의 Java 버전을 확인하십시오. 내 Weblogic 10.3.6이 TLSv1에 있던 JDK 1.7.0_75에 있었기 때문에 나에게 일어났습니다. 내가 사용하려는 나머지 끝점은 TLSv1.2 이하의 모든 것을 종료하는 것입니다.

기본적으로 Weblogic은 가장 강력한 공유 프로토콜을 협상하려고했습니다. 자세한 내용 은 HTTPS 연결을위한 https.protocols 시스템 속성 설정 관련 문제를 참조하세요 .

지원되는 TLS를 식별하기 위해 자세한 SSL 로깅을 추가했습니다. 이는 TLSv1이 핸드 셰이크에 사용 중임을 나타냅니다.
-Djavax.net.debug=ssl:handshake:verbose:keymanager:trustmanager -Djava.security.debug=access:stack

이 기능을 JDK8 호환 제품으로 푸시하여이 문제를 해결했습니다. JDK8의 기본값은 TLSv1.2입니다. JDK7로 제한된 사용자를 위해 TLSv1.2로 업그레이드하여 Java 7에 대한 해결 방법도 성공적으로 테스트했습니다. 이 답변을 사용했습니다 : Java 7에서 TLS 1.2를 활성화하는 방법


감사합니다. 제 문제를 해결할 새로운 방향을 보여 주셨습니다. 그리고 마침내 나는 그것이 사실임을 발견했습니다 !!!
karl li

1

SSH를 통해 서버에서 명령을 보내려는 Java 프로그램 에서도이 문제가 발생했습니다. 문제는 Java 코드를 실행하는 시스템에있었습니다. 원격 서버에 연결할 수있는 권한이 없습니다. write () 메소드는 잘 작동했지만 read () 메소드는 java.net.SocketException : 연결 재설정을 던졌습니다. 클라이언트 SSH 키를 알려진 원격 서버 키에 추가하여이 문제를 해결했습니다.


0

제 경험상, 저는 종종 다음과 같은 상황에 직면합니다.

  1. 회사에서 일하는 경우 네트워크 및 보안 팀에 문의하십시오. 외부 서비스에 대한 요청 에서 관련 엔드 포인트에 대한 권한부여 해야 할 수 있기 때문 입니다.

  2. 또 다른 문제는 애플리케이션이 실행중인 서버에서 SSL 인증서가 만료되었을 수 있다는 것 입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.