2012-08-06 2 views
9

나는 불확실한 시간 동안 데이터를 앞뒤로 푸시하기위한 클라이언트/서버 관계에서 작업하고 있습니다.C에서 소켓 연결 끊김을 감지하는 방법

내가 해결하려고하는 문제는 클라이언트 측에서 연결 끊김을 감지하는 방법을 찾을 수 없다는 것입니다.

다른 사람들의 솔루션에서 IO 예외를 잡는 것에서부터 세 개의 SelectMode 모두에서 소켓을 폴링하는 것에 이르기까지 몇 가지 단계를 거쳤습니다. 또한 소켓의 '사용 가능'필드에 대한 점검과 함께 설문 조사의 조합을 사용하여 시도했습니다. 서버 측에

// Something like this 
Boolean IsConnected() 
{ 
    try 
    { 
     bool part1 = this.Connection.Client.Poll(1000, SelectMode.SelectRead); 
     bool part2 = (this.Connection.Client.Available == 0); 

     if (part1 & part2) 
     { 
      // Never Occurs 
      //connection is closed 
      return false; 
     } 
     return true; 
    } 
    catch(IOException e) 
    { 
     // Never Occurs Either 
    } 
} 

은에 '빈'문자를 작성하는 시도가 (\ 0) 클라이언트에 IO 예외를 강제하고 서버는 클라이언트가 (아주 쉽게 공연을) 분리 것을 감지 할 수 있습니다.

클라이언트 측에서도 동일한 작업을 수행하면 예외가 발생하지 않습니다.

// Something like this 
Boolean IsConnected() 
{ 
    try 
    { 

     this.WriteHandle.WriteLine("\0"); 
     this.WriteHandle.Flush(); 
     return true; 
    } 
    catch(IOException e) 
    { 
     // Never occurs 
     this.OnClosed("Yo socket sux"); 
     return false; 
    } 
} 
내가 설문 조사를 통해 차단을 검출에 데 생각 문제는, 내 서버가 아직 있기 때문에 클라이언트에 다시 아무것도 작성하지 않은 경우 나는 비교적 쉽게하는 SelectRead에 허위가 발생할 수 있다는 것입니다

마지막 확인 ... 여기에 무엇을 해야할지 모르겠다. 나는이 옵션을 찾기 위해 모든 옵션을 쫓아 갔다. 찾을 수있는 것은 아무것도 아니고 나를 위해 100 % 아무것도하지 못했다. 궁극적으로 나의 목표는 서버 (또는 연결) 실패, 클라이언트에게 알리고, 다시 연결하기를 기다린다. 그래서 나는 이것이 당신에게 필수적인 부분이라는 것을 상상할 수있을 것이라고 확신한다.

누구의 제안도 감사하십시오. 미리 감사드립니다.

편집 :이 질문을 보는 사람은 아래의 대답과 그에 대한 나의 최종 의견을 적어 두어야합니다. 나는이 문제를 어떻게 극복했는지에 대해 자세히 설명했지만, 아직 'Q & A'스타일 포스트를 만들지 않았다.

+0

IOException을 catch하고 읽기 제한 시간을 사용하십시오. 이 다른 말라 키는 모두 필요하지 않습니다. – EJP

+0

나는 그것을 이미 시도했다. (당신이 정말로 내 글을 읽지 않았다면 ...) 그것은 치거나 맞았다. 두 번째 후에 읽기 작업 시간이 IO를 발생 시키면 강제로 연결 해제됩니다 ... 그러나 데이터를받지 못하면 어떻게됩니까? – DigitalJedi805

+0

귀하의 게시물을 읽었습니다. 그것은 '히트 앤 미스'가 아니며 로컬과 원격 모두 비동기 데이터 버퍼링의 영향을받습니다. 실패한 연결에 대한 첫 번째 쓰기는 아직 감지되지 않았으므로 예외가 발생하지 않습니다. TCP가 재시도 시간 제한을 초과 한 후 후속 쓰기에서이를 가져옵니다. – EJP

답변

12

하나의 옵션은 TCP 연결 유지 패킷을 사용하는 것입니다. Socket.IOControl()으로 전화를 걸어 켜십시오. .

Socket socket; //Make a good socket before calling the rest of the code. 
int size = sizeof(UInt32); 
UInt32 on = 1; 
UInt32 keepAliveInterval = 10000; //Send a packet once every 10 seconds. 
UInt32 retryInterval = 1000; //If no response, resend every second. 
byte[] inArray = new byte[size * 3]; 
Array.Copy(BitConverter.GetBytes(on), 0, inArray, 0, size); 
Array.Copy(BitConverter.GetBytes(keepAliveInterval), 0, inArray, size, size); 
Array.Copy(BitConverter.GetBytes(retryInterval), 0, inArray, size * 2, size); 
socket.IOControl(IOControlCode.KeepAliveValues, inArray, null); 

유지 : 만 짜증나는 비트가 입력으로 바이트 배열을 소요, 그래서 당신이 전달하는 바이트의 배열에 데이터를 변환 할 필요가 여기에 10000ms를 사용하는 예는 1000MS 재시도 살아 계속있어 활성 패킷은 다른 데이터를 전송하지 않을 때만 전송되므로 데이터를 보낼 때마다 10000ms 타이머가 재설정됩니다.

+0

굉장하고, 고마워. 조엘, 내가 데브 시스템에 충돌하자마자 바로 돌려 줄거야. – DigitalJedi805

+0

안녕하세요 조엘, 그래서 생각이 여기에 있지만 제발 정정하십시오 제발 잘못이라면; IOControl 메서드는 소켓에 'KeepAlive'패킷의 시간 초과 배달을 지정합니다. 위의 코드를 SocketServer.Client 및 SocketClient 생성자에 모두 추가했습니다. 나는 두 번째로 타이머를 줄였습니다. (양면에서 '읽기'가 타임 아웃 되었기 때문에?)하지만 StreamReader.ReadLine (그냥 내 타이핑이되어서이 전략을 쓰지 못한다는 것을 깨달았습니다. 왜 내가 우리가 배열에 넣고있는 것을 넣고 있는지 정확히 모르겠다. 그것을 줄 끝낼 수 있습니까? – DigitalJedi805

+0

실제로 StreamReader.Read 호출을 사용하여 동일한 작업을 실행하려고 시도했지만 어느 방향으로도 아무 것도 얻지 못했습니다. 이 개념을 완전히 이해하지 못했을 수도 있습니다. – DigitalJedi805

관련 문제