Socket.Listen에 전달된 backlog 인자의 의미
간단한 테스트를 해볼까요? ^^
TcpListener serverSock = new TcpListener(IPAddress.Any, 5000);
serverSock.Start(5); // Socket.Listen(5); 호출과 동일
TcpClient clientSocket = serverSock.AcceptTcpClient();
Thread.Sleep(Timeout.Infinite);
위와 같이 프로그램을 하는 경우, 클라이언트가 접속을 시도했을 때 몇번째부터 예외가 발생할까요? ^^
정답은 7입니다. 왜냐하면, 첫 번째 Connect 시도는 AcceptTcpClient 호출 덕분에 정상적으로
accept했기 때문에 backlog에 쌓이지 않습니다. 따라서 두 번째에서 여섯 번째까지의 Connect 시도가 backlog에 쌓여서 5개의 큐 제한을 꽉 채우게 됩니다. 그리고는 7번째 Connect 요청에 대해서는 서버 소켓이 명시적으로 오류를 내어 해당 클라이언트에서는 다음과 같은 예외가 발생합니다.
System.Net.Sockets.SocketException was unhandled
_HResult=-2147467259
_message=No connection could be made because the target machine actively refused it
HResult=-2147467259
IsTransient=false
Message=No connection could be made because the target machine actively refused it 192.168.0.23:5000
Source=System
ErrorCode=10061
NativeErrorCode=10061
StackTrace:
at System.Net.Sockets.TcpClient.Connect(String hostname, Int32 port)
at ConsoleApplication1.Program.ClientFunc(Object obj) in e:\...\ConsoleApplication1\Program.cs:line 115
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart(Object obj)
InnerException:
이 상태에서 netstat로 소켓 상태를 확인해 보면 6개의 TCP 자원이 "ESTABLISHED" 상태로 진입한 것을 확인할 수 있습니다.
c:> netstat -ano | findstr ":5000"
TCP 0.0.0.0:5000 0.0.0.0:0 LISTENING 2384
TCP 192.168.0.23:5000 192.168.0.95:62724 ESTABLISHED 2384
TCP 192.168.0.23:5000 192.168.0.95:62725 ESTABLISHED 2384
TCP 192.168.0.23:5000 192.168.0.95:62726 ESTABLISHED 2384
TCP 192.168.0.23:5000 192.168.0.95:62727 ESTABLISHED 2384
TCP 192.168.0.23:5000 192.168.0.95:62728 ESTABLISHED 2384
TCP 192.168.0.23:5000 192.168.0.95:62729 ESTABLISHED 2384
이때,
tcpview.exe와 같은 도구를 이용해 backlog에 쌓여 있는 "ESTABLISHED" 상태의 소켓을 강제로 닫으면 어떤 일이 발생할까요? 당연히 netstat로 확인하면 "ESTABLISHED" 상태의 소켓 수가 줄어들게 됩니다.
그렇다면 backlog에 쌓인 소켓 수가 줄었으니, 이후의 클라이언트 소켓 연결 요청을 받아들이게 될까요?
정답은, 받아들일 수 없습니다. 이를 통해서 소켓은 Listen에 지정된 숫자가 운영체제의 소켓 자원에 대한 '상태'와는 무관하게 계산된다는 것을 알 수 있습니다. 즉, Listen으로 인해 연결 요청이 들어온 것이 큐에 쌓이게 되고 그것이 빠져나가지 않는 한 해당 연결 요청에 대한 클라이언트 들의 상태와는 무관하게 accept 처리가 되는 것입니다.
(현실적으로 별로 유용한 정보는 아니지만, 그냥 심심해서 테스트 한번 해봤습니다. ^^)
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]