성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] VT sequences to "CONOUT$" vs. STD_O...
[정성태] NetCoreDbg is a managed code debugg...
[정성태] Evaluating tail call elimination in...
[정성태] What’s new in System.Text.Json in ....
[정성태] What's new in .NET 9: Cryptography ...
[정성태] 아... 제시해 주신 "https://akrzemi1.wordp...
[정성태] 다시 질문을 정리할 필요가 있을 것 같습니다. 제가 본문에...
[이승준] 완전히 잘못 짚었습니다. 댓글 지우고 싶네요. 검색을 해보...
[정성태] 우선 답글 감사합니다. ^^ 그런데, 사실 저 예제는 (g...
[이승준] 수정이 안되어서... byteArray는 BYTE* 타입입니다...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>C# - ReceiveTimeout, SendTimeout이 적용되지 않는 Socket await 비동기 호출</h1> <p> 예전 글에서,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C# - (예를 들어, Socket) 비동기 I/O에 대한 await 호출 시 CancellationToken을 이용한 취소 ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/13561'>https://www.sysnet.pe.kr/2/0/13561</a> </pre> <br /> .NET Framework 환경의 NetworkStream.WriteAsync 비동기 메서드가 CancellationToken에 반응하지 않는다고 했는데요, 이 문제는 NetworkStream.ReadAsync 메서드에서도 그대로 나타납니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Socket clntSocket = socket.Accept(); NetworkStream ns = new NetworkStream(clntSocket); while (true) { byte [] buffer = new byte[1024]; Console.WriteLine("Receive [before]"); <span style='color: blue; font-weight: bold'>CancellationTokenSource cts = new CancellationTokenSource(3000);</span> int received = <span style='color: blue; font-weight: bold'>await ns.ReadAsync</span>(buffer, 0, buffer.Length, <span style='color: blue; font-weight: bold'>cts.Token</span>); Console.WriteLine("Receive [after]"); } </pre> <br /> 위와 같이 실행하면, (클라이언트가 데이터를 전송하지 않는다고 가정하고) ns.ReadAsync는 3초 후에도 작업을 취소하지 못하고 await 콜백을 영원히 이어나가지 못합니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 이 외에도 NetworkStream은 Socket.ReceiveTimeout, Socket.SendTimeout에도 영향을 받지 않습니다. <a target='tab' href='https://www.sysnet.pe.kr/2/0/13561#netfx_apm'>이전 글</a>"에서 (.NET Framework에서 구현한) NetworkStream의 ...Async 메서드는 내부적으로 <a target='tab' href='https://www.sysnet.pe.kr/2/0/10939'>APM(Begin/End...) 비동기 메서드 호출</a>을 사용한다고 했는데요, <a target='tab' href='https://www.sysnet.pe.kr/2/0/13267#timeout_apm'>이로 인해 Socket의 timeout 설정들이 적용되지 않는 것</a>입니다.<br /> <br /> 그러니까 그냥 .NET Framework 환경에서 NetworkStream으로 비동기를 호출했을 때 timeout을 지정하는 것은 그냥 포기해야 합니다. (대신 <a target='tab' href='https://www.sysnet.pe.kr/2/0/13561#netfx_workaround'>우회 방법</a>으로.)<br /> <br /> 또한 Socket 타입에서도 SendAsync, ReceiveAsync가 제공되는데 이것 역시 SendTimeout, ReceiveTimeout에 영향을 받지 않습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <span style='color: blue; font-weight: bold'>clntSocket.ReceiveTimeout = 3000;</span> byte[] buffer = new byte[1024]; ArraySegment<byte> seg = new ArraySegment<byte>(buffer); <span style='color: blue; font-weight: bold'>await clntSocket.ReceiveAsync</span>(seg, SocketFlags.None); // 3초 지나도 await 이후의 콜백으로 진행하지 못함 // 참고로, (.NET Framework에서 구현한) Socket 타입의 SendAsync, ReceiveAsync는 CancellationToken 인자를 아예 받지 않습니다. </pre> <a name='timeout_doc'></a> <br /> 사실 마이크로소프트의 문서에서도 이에 대해 명시를 하고 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Socket.ReceiveTimeout Property ; <a target='tab' href='https://learn.microsoft.com/ko-kr/dotnet/api/system.net.sockets.socket.receivetimeout'>https://learn.microsoft.com/ko-kr/dotnet/api/system.net.sockets.socket.receivetimeout</a> Gets or sets a value that specifies the amount of time after which a <span style='color: blue; font-weight: bold'>synchronous Receive call</span> will time out. </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Socket.SendTimeout Property ; <a target='tab' href='https://learn.microsoft.com/ko-kr/dotnet/api/system.net.sockets.socket.sendtimeout'>https://learn.microsoft.com/ko-kr/dotnet/api/system.net.sockets.socket.sendtimeout</a> Gets or sets a value that specifies the amount of time after which a <span style='color: blue; font-weight: bold'>synchronous Send call</span> will time out. </pre> <br /> <br /> <hr style='width: 50%' /><br /> <br /> 그렇다면 .NET Core/5+ 환경은 어떨까요? 마찬가지로 Socket 타입의 경우 SendAsync, ReceiveAsync는 SendTimeout, ReceiveTimeout에 영향을 받지 않습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <span style='color: blue; font-weight: bold'>clntSocket.ReceiveTimeout = 3000;</span> byte[] buffer = new byte[1024]; ArraySegment<byte> seg = new ArraySegment<byte>(buffer); <span style='color: blue; font-weight: bold'>await clntSocket.ReceiveAsync</span>(seg, SocketFlags.None); // 3초 지나도 await 이후의 콜백으로 진행하지 못함 </pre> <br /> 하지만, .NET Framework과는 달리 CancellationToken을 받는 메서드를 제공하고 있으며,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Memory<byte> seg = new Memory<byte>(buffer); CancellationTokenSource cts = new CancellationTokenSource(3000); <span style='color: blue; font-weight: bold'>await clntSocket.ReceiveAsync</span>(seg, <span style='color: blue; font-weight: bold'>cts.Token</span>); // 3초 후에 "System.OperationCanceledException: The operation was canceled." 예외 발생 </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Memory<byte> seg = new Memory<byte>(buffer); CancellationTokenSource cts = new CancellationTokenSource(3000); <span style='color: blue; font-weight: bold'>await clntSocket.SendAsync</span>(seg, <span style='color: blue; font-weight: bold'>cts.Token</span>); // 3초 후에 "System.OperationCanceledException: The operation was canceled." 예외 발생 </pre> <br /> Cancel 동작이 잘 수행됩니다. 그러니까 .NET Core/5+는 비동기 환경의 경우 (<a target='tab' href='https://www.sysnet.pe.kr/2/0/13561#netcore_async'>NetworkStream에서와 동일하게</a>) CancellationToken으로 일관성있게 timeout 처리를 제공하고 있는 것입니다. </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
7521
(왼쪽의 숫자를 입력해야 합니다.)