TcpClient 연결을 적절하고 완전히 닫거나 재설정하는 방법은 무엇입니까?


78

TcpClient 연결을 닫거나 재설정하는 올바른 방법은 무엇입니까? 하드웨어와 통신하는 소프트웨어가 있지만 때때로 문제가 발생하여 소프트웨어를 다시 시작할 때까지 더 이상 통신 할 수 없습니다.

TcpClient.Close ()를 강제로 시도하고 null로 설정했지만 작동하지 않습니다. 소프트웨어를 완전히 다시 시작해야만 작동합니다.

제안?


TpcClient는 한 위치에만 정의되어 있지만 라이브러리 전체에서 사용되기 때문에 using 키워드를 사용할 수 없습니다. (그리고 주어진 시간에 하나의 연결 만 있습니다)

커뮤니케이션을 처리하는 라이브러리입니다. 소프트웨어 자체는 하드웨어를 나타내는 Controller 클래스의 ResetConnection () 메서드를 호출 할 수 있습니다.

현재는

if (tcpClient != null)
{
    tcpClient.Close();
    tcpClient = null;
}

이제 여기에서 읽은 내용에서 "= null"대신 tcpClient.Dispose ()를 사용해야합니다.

나는 그것을 시도하고 그것이 차이를 만드는지 볼 것입니다.

답변:


93

연결을 닫기 전에 스트림을 닫아야합니다.

tcpClient.GetStream().Close();
tcpClient.Close();

클라이언트를 닫아도 스트림이 닫히지 않습니다.


11
TcpClient를 닫아도 연결이 닫히지 않으면 도대체 어떻게 닫히나요? TcpClient를 닫아야하는 이유가 있습니까?
Qwertie 2011 년

정말 모르겠습니다. Reflector로 확인해야하지만 스트림이 아닌 사용 된 다른 객체를 닫을 수 있습니다 (스트림이 다른 객체간에 공유 될 수 있으므로 자동으로 닫히지 않고 추측 만하면됩니다).
Ignacio Soler Garcia

36
스트림을 닫아야 하는 버그 ( support.microsoft.com/kb/821625 )는 .NET 1.1 및 이전 버전에만 존재합니다. .NET 4.5에서 샘플 코드를 테스트했으며 스트림에서 close를 호출하지 않고도 정상적으로 작동합니다.
Anssssss 2014 년

4
tcpClient.Client.Close () 또는 tcpClient.GetStream (). Close () 대신 tcpClient.Close ()를 사용하면 .NET 4.6.1에서 여전히 간헐적 인 문제가 발생합니다. 나는 이것을 발견 할 때까지 얼마 전 정신을 잃을 뻔했다.
Mike Marynowski

.NET 표준의로 System.Net.Sockets.TcpClient, 전화 Dispose(). 방법이 없습니다 Close().
NathanAldenSr

27

받아 들여지는 답변이 구식이고 이것에 관한 다른 답변에는 아무것도 보이지 않는다는 점을 감안할 때 새 답변을 만들고 있습니다. .Net 2 및 이전 버전에서는 연결을 닫기 전에 스트림을 수동으로 닫아야했습니다. 이 버그는 TcpClientC # 의 모든 이후 버전에서 수정되었으며 Close 메서드 문서에 명시된대로 메서드 를 호출 Close하면 연결과 스트림이 모두 닫힙니다.

Microsoft Docs에 따라 편집

Close 메서드는 인스턴스를 삭제 된 것으로 표시하고 연결된 Socket이 TCP 연결을 닫도록 요청합니다. LingerState 속성에 따라 TCP 연결은 데이터를 계속 보낼 때 Close 메서드가 호출 된 후 얼마 동안 열려있을 수 있습니다. 기본 연결이 종료되면 알림이 제공되지 않습니다.

이 메서드를 호출하면 결국 연결된 소켓이 닫히고 데이터를 보내고받는 데 사용되는 연결된 NetworkStream도 닫힙니다.


@Twometer 어떤 버전의 .Net을 타겟팅하고 있습니까?
John Demetriou 2018

그것은 .NET 4.6.1
Twometer 2011

TcpClient.Close (), tcpClient.Client.Close (), .Disconnect () 무엇이든 호출하고 있으며 닫히지 않습니다. 프로세스를 종료 할 때만 서버에 "연결이 닫혔습니다."라는 메시지가 표시됩니다
Twometer

링크 한 기사의 예제는을 (를) 호출 networkStream.Close();하기 전에 호출 tcpClient.Close();하므로 예제가 오래되었거나 기본 스트림을 수동으로 닫아야합니다.
Deantwo

@Deantwo 내 대답을 업데이트했습니다. 폐기 준비가 된 것으로 표시됩니다. 그러나 폐기 될시기에 대한 보장은 없습니다.
John Demetriou

22

사용 단어 : using. 좋은 프로그래밍 습관.

using (TcpClient tcpClient = new TcpClient())
{
     //operations
     tcpClient.Close();
}

42
모든 모델에 적용되는 것은 아닙니다. 하나의 코드 블록 내에서 일시적으로 연결을 사용하는 경우 유용하지만 연결을 구성원으로 유지하려는 클라이언트 구현이있는 경우이 메서드는 실패합니다. 또한 클래스 설명서에 따라 TcpClient에서 Dispose ()를 호출해도 기본 소켓이 닫히지 않는다는 것을 알 수 있습니다. 사용하면 폐기됩니다.
Gusdor 2011

1
이것은 비동기 및 비 차단 소켓에서 작동하지 않으며 실제로 연결을 어딘가에 저장하고 관리하려는 경우이 코드를 사용할 수 없습니다.
Kas

7
@Gusdor 반영된 소스를 보면 Dispose (true)가 클라이언트에서 Close ()를 호출하는 것 같습니다. (.NET 4.0)
폐기

새로 추가 된 것이어야합니다. .net 3.5를 참고하여 게시했습니다. 잘 발견되었습니다!
Gusdor

1
@Dermot, @SteveJobs 글쎄, 이제 미래는 async키워드 와 함께 여기에 있으므로 ;-). 블록 내부에서 호출하면 BeginConnect()및 와도 호환됩니다 .EndConnect()End…using
binki

8

모든 적절한 using명령문을 가지고 있음에도 불구하고 , 호출 Close, 지수 백 오프 논리 및 TcpClient다시 생성 응용 프로그램을 다시 시작하지 않으면 응용 프로그램이 TCP 연결을 복구 할 수없는 문제가 여전히 발생했습니다. 계속해서 System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.

그러나 옵션이 있습니다 LingerStateTcpClient이 문제를 해결 한 수 표시 (내 자신의 하드웨어 설정은 종종 그것에 대해 실패로 몇 달 동안 모를 수는!). MSDN을 참조하십시오 .

// This discards any pending data and Winsock resets the connection.
LingerOption lingerOption = new LingerOption(true, 0);

using (var tcpClient = new TcpClient 
       {SendTimeout = 2000, ReceiveTimeout = 2000, LingerState = lingerOption })
   ...

안녕! 나는 모든 적절한 코드를 가지고 있음에도 불구하고 때때로이 예외가 무작위로 나타나는데도 LingerOption이 문제를 해결 했습니까? 이 간헐적 인 문제를 없애기 위해 모든 코드를 UDP로 마이그레이션하는 것을 진지하게 생각하고 있습니다
Rafael

@rafael 나는 그것이 내 문제를 해결했다고 생각한다. 나는 이것을 게시 한 이후로이 문제를 전혀 보지 못했다.
Ian Mercer

6

소켓 연결을 닫고 소켓의 재사용을 허용합니다.

tcpClient.Client.Disconnect(false);

1
나중에 연결을 다시 열려면 왜 이렇게해야하는지 혼란 스럽습니다. 스트림을 닫고 TcpClient다음을 닫으면 나중에 예외가 발생합니다 .Connect.
pep

6
Disconnect (true)를 의미하지 않습니까?
WDUK

6

다시 열 수 있도록 소켓을 닫는 올바른 방법은 다음과 같습니다.

tcpClient.Client.Disconnect(true);

Boolean 매개 변수는 소켓을 재사용할지 여부를 나타냅니다.

연결 해제 방법 사용


5

일부 내부 로깅을 제외하고 Close == Dispose.

Dispose는 tcpClient.Client.Shutdown (SocketShutdown.Both)을 호출하지만 오류가 발생합니다. 직접 호출하면 유용한 예외 정보를 얻을 수 있습니다.


1

TcpClient.Dispose ()를 명시 적으로 호출 해 보셨습니까 ?

그리고 TcpClient.Close () 및 TcpClient.Dispose ()-ed 모든 연결 이 있는지 확신 합니까?


연결이 하나 뿐이고 닫았지만 폐기하지 않았습니다 ... 그게 차이가나요? (그렇다고 생각합니다, 그냥 묻습니다 :-)
TimothyP

TcpClient.Dispose는 보호되며 직접 호출 할 수 없습니다.
theycallmemorty

@theycallmemorty doc은 그렇지 않다고 말합니다. msdn.microsoft.com/en-us/library/vstudio/…
chakrit

2
명시적인 인터페이스 구현입니다. 그것은 보이지 어린 아이를, 그래서 그는 예는 IDisposable에 그것의 주조까지하여 TcpClient를 입력((IDisposable)client).Dispose()
조셉 레녹스
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.