Java socket API: 연결이 종료되었는지 확인하는 방법
Java socket API에 몇 가지 문제가 있습니다.현재 게임에 연결된 플레이어의 수를 표시하려고 합니다.플레이어가 접속한 타이밍을 쉽게 판별할 수 있습니다.그러나 소켓 API를 사용하여 플레이어가 언제 연결이 끊겼는지 판단하는 것은 불필요하게 어려워 보입니다.
" "isConnected()
, 항상 「반환」이 되는 것 .true
「」를 호출합니다isClosed()
에서는, 「귀환」이 되는 것 .false
소켓이 닫혔는지 아닌지를 실제로 판단하기 위해서는 출력 스트림에 데이터를 쓰고 예외를 포착해야 한다고 읽은 적이 있습니다.이것은 이 상황을 처리하는 정말 부정한 방법인 것 같다.소켓이 언제 닫혔는지 알기 위해서는 네트워크를 통해 스팸 메시지를 계속 보내야 합니다.
다른 해결책이 있나요?
TCP API를 사용합니다. isConnected()
★★★★★★★★★★★★★★★★★」isClosed()
소켓의 현재 상태를 나타냅니다.같은 게 아니에요.
isConnected()
에, 이 소켓이 접속되어 있는지 여부를 나타냅니다.그래, 그러니까 사실로 돌아온다isClosed()
에, 이 소켓을 닫았는지 여부를 나타냅니다.그렇지 않으면 false가 반환됩니다.피어가 정상적으로 접속을 종료했을 경우
read()
을 반환한다.readLine()
null
readXXX()
EOFException
XXXX입니다.를 쓰면 글씨가
IOException
'은 지연의 을 받습니다 '피어에 의한 접속 리셋'은 최종적으로 버퍼링 지연의 영향을 받습니다.
, 는 '하다', '다', '다', '다', '다', '다', '다', '다', '다', '다', '다', '다', '다'를 던집니다.
IOException
위와 같이, 최종적으로 와 판독에서도 같은 일이 발생할 수 있습니다.피어가 아직 연결되어 있지만 연결을 사용하지 않는 경우 읽기 시간 초과를 사용할 수 있습니다.
다른 곳에서 읽으실 수 있는 글과는 달리
ClosedChannelException
어느 쪽도 아니다]SocketException: socket closed.
채널을 닫은 후 계속 사용했다는 것만 알 수 있습니다.즉, 프로그래밍 오류입니다.접속이 닫혀 있는 것은 아닙니다.Windows XP에서 Java 7을 사용한 몇 가지 실험 결과 다음과 같은 경우도 있습니다.
- 를 고르는 거예요.
OP_READ
select()
보다 큰 됩니다.- 있는 것
SelectionKey
는 이미 무효입니다( ).key.isValid() == false
)
이는 피어가 접속을 리셋했음을 의미합니다.단, 이는 JRE 버전 또는 플랫폼 중 하나에 고유할 수 있습니다.
- 를 고르는 거예요.
다양한 메시징 프로토콜에서는 패킷의 크기가 그다지 크지 않아도 서로 하트비트를 유지(ping 패킷을 계속 전송)하는 것이 일반적입니다.프로빙 메커니즘에 의해 TCP가 일반적으로 검출하기 전에 절단된 클라이언트를 검출할 수 있습니다(TCP 타임아웃이 훨씬 높음).프로브를 송신하고 응답을 5초간 기다립니다.예를 들어 2-3 이후의 프로브에 대한 응답이 표시되지 않으면 플레이어는 절단됩니다.
그리고 관련 질문
방금 게시된 다른 답변은 확인했습니다만, 게임을 플레이하는 클라이언트와 대화하고 있다고 생각하기 때문에, 다른 어프로치를 제안할 수도 있습니다(Buffered Reader는 확실히 유효합니다.
당신이 원한다면...「등록」의 책임을 클라이언트에 위임할 수 있습니다.즉, 각 사용자로부터 수신한 마지막 메시지의 타임스탬프와 함께 연결된 사용자 컬렉션이 있습니다.클라이언트의 타임아웃이 발생했을 경우 클라이언트의 재등록을 강제하게 됩니다만, 그 결과 다음과 같은 견적을 얻을 수 있습니다.
소켓이 닫혀 있는지 여부를 실제로 판단하려면 출력 스트림에 데이터를 쓰고 예외를 포착해야 한다고 읽은 적이 있습니다.이것은 이 상황을 처리하는 정말 부정한 방법인 것 같다.
Java 코드가 소켓을 닫거나 연결을 해제하지 않으면 원격 호스트가 연결을 닫았다는 통보를 어떻게 받습니까?최종적으로 시도/캐치는 실제 소켓에서 이벤트를 리슨하는 폴러와 거의 같은 동작을 합니다.다음 사항을 고려하십시오.
- 로컬 시스템이 통지 없이 소켓을 닫을 수 있습니다.이것은 소켓의 실장일 뿐입니다(즉, 하드웨어/드라이버/펌웨어/상태변화를 위해 폴링하지 않습니다).
- 새 소켓(프록시 p)...복수의 파티(실제로 6개의 엔드 포인트)가 있어, 접속을 종료할 가능성이 있습니다.
추상화된 언어의 특징 중 하나는 당신이 미니어로부터 추상화되어 있다는 것이라고 생각합니다.SqlConnection 등의 경우 C#(try/finally)의 using 키워드를 생각해 주십시오.단지 사업을 하는 데 드는 비용일 뿐이야소켓의 경우 try/catch/finally가 허용되고 필요한 패턴이라고 생각합니다.
저도 비슷한 문제에 직면했어요.제 경우 클라이언트는 정기적으로 데이터를 전송해야 합니다.★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ SO_TIMEOUT을 SO_TIMEOUT으로 설정합니다.socket.setSoTimeout(1000 * 60 * 5);
입니다.java.net.SocketTimeoutException
지정된 시간이 만료된 경우.그러면 죽은 고객을 쉽게 발견할 수 있습니다.
이것이 tcp 접속의 성질이라고 생각합니다.이 표준에서는, 발신 접속이 없어질 때까지 약 6분간의 무음 상태가 됩니다.그래서 이 문제에 대한 정확한 해결책을 찾을 수 없을 것 같습니다.서버가 사용자 접속을 닫았을 경우를 추측하기 위해 편리한 코드를 작성하는 것이 좋습니다.
@user207421이 말하는 것처럼 TCP/IP 프로토콜 아키텍처 모델 때문에 연결의 현재 상태를 알 수 있는 방법은 없습니다.따라서 서버는 연결을 닫기 전에 사용자를 통지해야 합니다. 그렇지 않으면 사용자가 직접 확인해야 합니다.
다음으로 서버에 의해 소켓이 닫혀 있는지 확인하는 간단한 예를 나타냅니다.
sockAdr = new InetSocketAddress(SERVER_HOSTNAME, SERVER_PORT);
socket = new Socket();
timeout = 5000;
socket.connect(sockAdr, timeout);
reader = new BufferedReader(new InputStreamReader(socket.getInputStream());
while ((data = reader.readLine())!=null)
log.e(TAG, "received -> " + data);
log.e(TAG, "Socket closed !");
다음은 모든 데이터 유형에 대한 또 다른 일반적인 솔루션입니다.
int offset = 0;
byte[] buffer = new byte[8192];
try {
do {
int b = inputStream.read();
if (b == -1)
break;
buffer[offset++] = (byte) b;
//check offset with buffer length and reallocate array if needed
} while (inputStream.available() > 0);
} catch (SocketException e) {
//connection was lost
}
//process buffer
그게 내 방식이야
while(true) {
if((receiveMessage = receiveRead.readLine()) != null ) {
System.out.println("first message same :"+receiveMessage);
System.out.println(receiveMessage);
}
else if(receiveRead.readLine()==null)
{
System.out.println("Client has disconected: "+sock.isClosed());
System.exit(1);
} }
result.code == null인 경우
Linux 에서는 상대방이 모르는 소켓에 write()를 삽입할 때 SIGPIPE 신호/예외를 호출하고 싶은 대로 트리거합니다.그러나 SIGPIPE에 의해 잡히고 싶지 않은 경우 MSG_NOSIGNAL 플래그를 사용하여 send()를 사용할 수 있습니다.send() 콜은 -1로 반환됩니다.이 경우 errno를 체크하면 errno.h에 따라 32에 상당하는 EPIPE 값으로 끊어진 파이프(이 경우 소켓)를 쓰려고 했음을 알 수 있습니다.EPIPE에 대한 반응으로 소켓을 다시 열고 정보를 다시 전송해 보십시오.
언급URL : https://stackoverflow.com/questions/10240694/java-socket-api-how-to-tell-if-a-connection-has-been-closed
'source' 카테고리의 다른 글
php의 "include"와 "require"의 차이 (0) | 2023.01.15 |
---|---|
하위 쿼리에 그룹 열이 있을 때 MySQL 8이 INDEX를 사용하지 않습니다. (0) | 2023.01.15 |
Laravel 데이터베이스에서 모델을 새로고침/새로 고치는 방법 (0) | 2023.01.15 |
SQLite - RAND()로 주문 (0) | 2023.01.15 |
PHP/MySQL 행을 삽입한 후 'id'를 가져옵니다. (0) | 2023.01.15 |