성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] 그냥 RSS Reader 기능과 약간의 UI 편의성 때문에 사용...
[이종효] 오래된 소프트웨어는 보안 위협이 되기도 합니다. 혹시 어떤 기능...
[정성태] @Keystroke IEEE의 문서를 소개해 주시다니... +_...
[손민수 (Keystroke)] 괜히 듀얼채널 구성할 때 한번에 같은 제품 사라고 하는 것이 아...
[정성태] 전각(Full-width)/반각(Half-width) 기능을 토...
[정성태] Vector에 대한 내용은 없습니다. Vector가 닷넷 BCL...
[orion] 글 읽고 찾아보니 디자인 타임에는 InitializeCompon...
[orion] 연휴 전에 재현 프로젝트 올리자 생각해 놓고 여의치 않아서 못 ...
[정성태] 아래의 글에 정리했으니 참고하세요. C# - Typed D...
[정성태] 간단한 재현 프로젝트라도 있을까요? 저런 식으로 설명만 해...
글쓰기
제목
이름
암호
전자우편
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'>윈도우 서버 환경에서 클라이언트 소켓의 최대 접속 수</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;' > 윈도우 서버 환경에서, 최대 생성 가능한 소켓(socket) 연결 수는 얼마일까? ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/964'>https://www.sysnet.pe.kr/2/0/964</a> Configure the max limit for concurrent TCP connections ; <a target='tab' href='http://smallvoid.com/article/winnt-tcpip-max-limit.html'>http://smallvoid.com/article/winnt-tcpip-max-limit.html</a> </pre> <br /> 윈도우에서 최대 TcpConnection 수를 알아봤는데요, 일단 마이크로소프트의 공식 문서에는 다음의 자료로 찾아볼 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > the Win32_NetworkAdapterConfiguration class ; <a target='tab' href='https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/settcpnumconnections-method-in-class-win32-networkadapterconfiguration'>https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/settcpnumconnections-method-in-class-win32-networkadapterconfiguration</a> </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > TcpNumConnections [in] Maximum number of connections that TCP may have open simultaneously. The valid range of values is 0 - 0xFFFFFE. </pre> <br /> 윈도우는 내부적으로 저렇게 제한을 두는 것인데 다시 저 글을 읽어 보니 좀 의문이 남습니다. TCP 연결 구분을 [src_ip:port][dst_ip:port] 쌍으로 한다면 4바이트+2바이트+4바이트+2바이트이므로 2<sup>96</sup> 정도가 되어야 하는데 왜 약 3바이트 정도에서 마무리했던 건지 뒷이야기가 궁금합니다. (물론 천6백만 개의 동시 연결이 결코 부족하다고 볼 수는 없지만!)<br /> <br /> <hr style='width: 50%' /><br /> <br /> 그건 그렇고, "<a target='tab' href='https://www.sysnet.pe.kr/2/0/964'>윈도우 서버 환경에서, 최대 생성 가능한 소켓(socket) 연결 수는 얼마일까?</a>" 글에 남긴 Luna 님의 의견은 클라이언트 소켓인 경우 순수하게 클라이언트 측의 "포트 범위"로 제약이 걸린다는 것입니다.<br /> <br /> 한번 확인을 해볼까요? 절차는 다음과 같이 진행하면 될 듯합니다.<br /> <br /> <ol> <li>TCP 서버를 15000, 15001 포트를 열고,</li> <li>클라이언트에서 15000 서버로 포트가 소진될 만큼 열기를 시도하고,</li> <li>2번 단계에서 더 이상 열 수 없을 때, 15001 포트로의 연결이 가능한가?</li> </ol> <br /> <a name='maxuserport'></a> 여기서 포트가 소진되는 것은 너무 많으면 테스트가 귀찮아지니, 그냥 MaxUserPort 레지스트리 값을 2000(0x7d0)으로 손봐서,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 경로: HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Tcpip\Parameters 이름: MaxUserPort 타입: DWORD 값: 7d0 (2000) </pre> <br /> 테스트를 할 텐데 그럼 1024번을 시작으로 2000번까지 총 977개의 포트가 가용한 것으로 나옵니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C:\WINDOWS\system32> <span style='color: blue; font-weight: bold'>netsh int ipv4 show dynamicport tcp</span> Protocol tcp Dynamic Port Range --------------------------------- Start Port : 1024 Number of Ports : <span style='color: blue; font-weight: bold'>977</span> </pre> <br /> <a name='srv_code'></a> 이제 서버 프로그램을 만들고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Threading; namespace ConsoleApp1 { class Program { static List<TcpClient> _cla15000 = new List<TcpClient>(); static List<TcpClient> _cla15001 = new List<TcpClient>(); static void Main(string[] args) { Thread t = new Thread(CountFunc); t.IsBackground = true; t.Start(); Thread t15000 = new Thread(acceptFunc); t15000.IsBackground = true; t15000.Start(15000); Thread t15001 = new Thread(acceptFunc); t15001.IsBackground = true; t15001.Start(15001); Console.ReadLine(); } private static void acceptFunc(object objPort) { int port = (int)objPort; TcpListener svr = new TcpListener(IPAddress.Any, port); { svr.Start(); while (true) { TcpClient client = svr.AcceptTcpClient(); if (port == 15000) { _cla15000.Add(client); } else { _cla15001.Add(client); } } } } private static void CountFunc() { while (true) { Console.WriteLine($"# of 15000: {_cla15000.Count}, 15001: {_cla15001.Count}"); Thread.Sleep(1000); } } } } </pre> <br /> 클라이언트를 만들어,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; namespace ConsoleApp2 { class Program { static void Main(string[] args) { string ipAddr = args[0]; int port = int.Parse(args[1]); int numberOf = int.Parse(args[2]); List<TcpClient> clients = new List<TcpClient>(); try { for (int i = 0; i < numberOf; i++) { TcpClient client = new TcpClient(); client.Connect(ipAddr, port); clients.Add(client); } } catch { } Console.WriteLine(clients.Count); Console.ReadLine(); } } } </pre> <br /> (<a target='tab' href='https://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=1632&boardid=331301885'>첨부 파일은 이 글의 예제 코드를 포함</a>합니다.)<br /> <br /> 실행해 보면,<br /> <br /> <a name='output'></a> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C:\temp2> <span style='color: blue; font-weight: bold'>ConsoleApp1.exe</span> # of 15000: 0, 15001: 0 # of 15000: 0, 15001: 0 # of 15000: 0, 15001: 0 # of 15000: 0, 15001: 0 # of 15000: 0, 15001: 0 # of 15000: 966, 15001: 0 # of 15000: 966, 15001: 0 </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C:\temp2> <span style='color: blue; font-weight: bold'>ConsoleApp2 localhost 15000 1000</span> 966 </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C:\temp2> <span style='color: blue; font-weight: bold'>ConsoleApp2 localhost 15001 10000</span> 0 </pre> <br /> 결과는, 클라이언트용 소켓에 대해 dynamicport로 가용한 수를 모두 소진한 경우, 별도의 포트로 연결하지 못하고 있습니다. 즉, Luna 님의 의견대로 클라이언트 소켓의 경우 순수하게 포트 기준으로 제약을 가하고 있는 것입니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 그런데, Luna 님의 마지막 덧글이 좀 혼란스럽군요. 레지스트리의 MaxUserPort 값을 건드리지 않은 5000 상태라고 했는데 그럼 1,024번부터 5,000번까지 3,977개의 dynamicport 할당이 가능하고 따라서 그 숫자 내에서 ENOBUFS 오류가 발생해야 합니다. 하지만, 1만 개는 잘 되었고 2만 개 테스트 도중 해당 오류가 발생했다고 하니 이론상 맞지 않는데요.<br /> <br /> 이것은 아마도 MaxUserPort 값을 건드리지 않았다기보다는, 근래의 Windows 10에서는 MaxUserPort 값이 정의되어 있지 않아 dynamicport의 기본 값이 사용된 것으로 보입니다. net 명령어로 확인해 보면 다음과 같은 값이 나올 텐데요,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // MaxUserPort가 레지스트리에 없는 경우 C:\WINDOWS\system32> <span style='color: blue; font-weight: bold'>netsh int ipv4 show dynamicport tcp</span> Protocol tcp Dynamic Port Range --------------------------------- Start Port : 49152 Number of Ports : 16384 </pre> <br /> 따라서 16,384개의 클라이언트 소켓 연결을 할 수 있으므로, 두 번째 시도의 1만 개 테스트에서 ENOBUFS 오류가 발생했을 것으로 보입니다. (또한 당연하겠지만, 65,000여 개의 소켓 연결을 하고 싶다면 MaxUserPort 값을 65534로 높이면 됩니다. 그럼 "Number of Ports"의 값이 64511로 됩니다.)<br /> <br /> <hr style='width: 50%' /><br /> <br /> 참고로 문서상으로는,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 5000보다 큰 TCP 포트에서 연결하려고 하면 'WSAENOBUFS(10055)' 오류가 발생함 ; <a target='tab' href='https://support.microsoft.com/ko-kr/help/196271/when-you-try-to-connect-from-tcp-ports-greater-than-5000-you-receive-t'>https://support.microsoft.com/ko-kr/help/196271/when-you-try-to-connect-from-tcp-ports-greater-than-5000-you-receive-t</a> </pre> <br /> MaxUserPort의 유효 범위가 5000 ~ 65534라고 나오지만, 실제로 이 글에서 테스트한 것처럼 2,000도 허용이 되었습니다. (아마도, 위의 문서가 2003 버전 시절이라서 이후에 바뀌었을 듯합니다.)<br /> <br /> 또한 시험 삼아, MaxUserPort 값을 1000으로 낮췄더니 최소 시작은 1024번부터여서 그런지 이런 상태에서는 기본 범위로 잡는 것을 볼 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // MaxUserPort == 1000으로 설정한 경우, C:\WINDOWS\system32> <span style='color: blue; font-weight: bold'>netsh int ipv4 show dynamicport tcp</span> Protocol tcp Dynamic Port Range --------------------------------- Start Port : 49152 Number of Ports : 16384 </pre> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1211
(왼쪽의 숫자를 입력해야 합니다.)