NamedPipeServerStream.WaitForConnectionAsync(CancellationToken) 메서드가 토큰이 취소됐음에도 무기한 대기할 때 해결 방법

NamedPipeServerStream

NamedPipeServerStream

C#에서는 Named Pipe를 손쉽게 사용하기 위한 클래스인 NamedPipeServerStream, NamedPipeClientStream을 지원합니다. 이 중 NamedPipeServerStream은 그 이름에서 알 수 있듯 서버 기능 구현을 위한 스트림입니다.

연결 대기

서버는 당연히 클라이언트가 있어야 의미가 있습니다. 서버 혼자서는 아무것도 할 게 없기 때문이죠. 이런 당연한 얘기는 제쳐두고, 서버를 구현하다 보면 자연스레 클라이언트가 연결이 됐는지 안 됐는지 확인하는 코드가 필요하게 됩니다.

TCP 소켓 같은 경우에는, AcceptAsync 등을 사용해 아예 클라이언트 소켓 자체를 받아오거나, Pending 메서드를 사용해 접속 대기중인 클라이언트가 있는지 확인할 수 있습니다. 그럼 NamedPipeServerStream에는 뭐가 있을까요?

WaitForConnection, WaitForConnectionAsync

당연히 NamedPipeServerStream에도 클라이언트 접속 여부를 판단하는 메서드가 있습니다. 바로 WaitForConnection, WaitForConnectionAsync입니다.

첫 번째 메서드는 동기 방식으로 대기합니다. 이 경우에는 해당 메서드가 호출된 시점부터 클라이언트가 접속할 때까지 호출된 스레드가 블럭됩니다.

이번 포스트에서 다룰 것은 두 번째 메서드, WaitForConnectionAsync입니다.

CancellationToken

WaitForConnectionAsync 메서드는 인자로 CancellationToken을 받을 수 있습니다. 따라서, 해당 토큰에 취소 요청이 받아들여지면 대기를 중지하고 OperationCanceledException 예외를 발생시켜야 합니다. 그러나, 어째서인지 아무리 취소 요청을 전달해봐도 소식이 없었습니다.

제 코드에는 서버의 현재 상태를 나타내기 위해 bool IsRunning { get; set; } 프로퍼티가 존재합니다. 혹시 캐시된 상태 정보 때문에 계속 블럭되는 것인가 하는 생각에 해당 프로퍼티를 필드로 변경하고 volatile 키워드를 붙여 상태가 캐시되지 않도록 했습니다만, 그래도 여전히 증상은 같았습니다.

NamedPipeServerStream의 생성자, PipeOptions

오늘도 열심히 굽어 살피시는 구글신과 스택오버플로우 덕분에 문제를 해결하긴 했습니다만, 사실 이렇게까지 하지 않아도 MSDN만 잘 읽어보면 해결할 수 있는 문제였습니다.

아무튼, 원인은 다음과 같았습니다. NamedPipeServerStream.WaitForConnectionAsync(CancellationToken) 메서드에 전달된 인자인 CancellationToken은, 해당 인스턴스가 생성될 때 PipeOptions.Asynchronous 인자가 전달되어야만 정상적으로 작동한다고 합니다.[1][2]

해결 방법은 PipeOptions.Asynchronous를 생성자에 전달

해당 문서들에 따르면, 해결 방법은 NamedPipeServerStream의 생성자에 PipeOptions.Asynchronous를 전달하는 것입니다.

테스트 결과 정상 작동하는 것을 확인했습니다.

오늘도 다시 한 번, 문서를 꼼꼼히 살펴봐야 하겠다는 다짐만 하고 갑니다. 그도 그럴 게, 구글이 있는 걸요.


  1. CancellationToken not working with WaitForConnectionAsync ↩︎

  2. MSDN NamedPipeServerStream.WaitForConnectionAsync - Remarks ↩︎

댓글

이 블로그의 인기 게시물

C# 남아도는 메모리에도 불구하고 OutOfMemoryException이 발생한다면?

USB를 뒤는 괜찮은데 앞에 꽂으면 인식이 힘들다?

MySQL 데이터 타입과 Java 데이터 타입 비교/매칭