성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
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'>UDP 브로드캐스팅을 이용해 서비스 측의 IP 주소를 구하는 방법</h1> <p> 프로그램을 만들다 보면, 사용자에게 IP 주소를 입력받는 경우가 생기는데요. 이 작업이 다소 귀찮은 것이 사실입니다. 다행히 (UDP 패킷이 전달되는) 같은 네트워크 내에 소켓 클라이언트/서버가 있다면 이 작업을 UDP 브로드캐스팅으로 간단하게 해결할 수 있습니다.<br /> <br /> 우선, 서비스를 제공하는 측의 프로그램에서는 다음과 같이 UDP 소켓을 열어 Receive로 대기해 놓아야 합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // ============= 서버 측 프로그램 ============= private static void StartListener() { bool done = false; UdpClient listener = new UdpClient(listenPort); // 11000번 포트로 UDP 브로드캐스팅 패킷을 수신하기 위한 접점 정보 구성 IPEndPoint groupEP = new IPEndPoint(<span style='color: blue; font-weight: bold'>IPAddress.Broadcast, 11000</span>); while (!done) { // UDP 브로드캐스팅 패킷을 수신 byte[] bytes = <span style='color: blue; font-weight: bold'>listener.Receive</span>(ref groupEP); // 블록킹 상태로 진입 // ... 생략 ... } listener.Close(); } </pre> <br /> 그럼, 해당 서비스를 찾는 클라이언트 측에서는 UDP 소켓을 이용해 패킷을 현재 망에 뿌려주면 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // ============= 클라이언트 측 프로그램 ============= static void Main(string[] args) { Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); <span style='color: blue; font-weight: bold'>s.EnableBroadcast = true;</span> byte[] sendbuf = Encoding.ASCII.GetBytes("HELLO"); EndPoint targetEndPoint = new IPEndPoint(<span style='color: blue; font-weight: bold'>IPAddress.Broadcast, 11000</span>); // UDP 브로드캐스팅 패킷을 네트워크에 전송 s.SendTo(sendbuf, targetEndPoint); // ... 생략 ... } </pre> <br /> 클라이언트 측의 SendTo로 브로드캐스팅 패킷이 네트워크에 뿌려지면 서버 측에서 대기 중인 listener.Receive가 이를 수신하게 됩니다. 그럼, 서버는 자신의 IP 주소를 상대방에게 전송함으로써 서비스가 대기 중인 IP 주소를 알릴 수 있습니다.<br /> <br /> 그런데, 여기서 한 가지 주의해야 할 사항이 있는데요. 서버에는 네트워크 어댑터의 수에 따라 다양한 IP 주소가 할당될 수 있고, 그 중에는 클라이언트 측 IP 주소와 동일한 네트워크를 공유하지 않는 경우도 발생할 수 있으므로 아무 IP나 전송해서는 안됩니다. 가능하다면 서브넷 마스크값을 확인해서 그에 대응되는 IP 주소 값을 보내주는 것이 좋은데, 이에 대해서는 다음과 같은 방식으로 구할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > private static void StartListener() { // ... 생략 ... byte[] bytes = listener.Receive(ref groupEP); <span style='color: blue; font-weight: bold'>string txt = FindUdpEndpoint(groupEP);</span> // ... 생략 ... } private static string FindUdpEndpoint(IPEndPoint groupEP) { byte[] clntAddress = groupEP.Address.GetAddressBytes(); foreach (var item in GetInetAddress(AddressFamily.InterNetwork)) { byte[] svrAddress = item.Item1.GetAddressBytes(); byte[] maskAddress = item.Item2.GetAddressBytes(); bool match = true; for (int i = 0; i < maskAddress.Length; i++) { if (maskAddress[i] == 0xFF) { if (svrAddress[i] != clntAddress[i]) { match = false; break; } } else { break; } } if (match == true) { return item.Item1.ToString(); } } return null; } public static Tuple<IPAddress, IPAddress>[] GetInetAddress(System.Net.Sockets.AddressFamily family) { List<Tuple<IPAddress, IPAddress>> ipAddresses = new List<Tuple<IPAddress, IPAddress>>(); NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces(); foreach (NetworkInterface nic in nics) { foreach (UnicastIPAddressInformation uni in nic.GetIPProperties().UnicastAddresses) { if (uni.Address.AddressFamily == family) { if (System.Net.IPAddress.Loopback.ToString() == uni.Address.ToString()) { continue; } <span style='color: blue; font-weight: bold'>ipAddresses.Add(Tuple.Create(uni.Address, uni.IPv4Mask));</span> } } } return ipAddresses.ToArray(); } </pre> <br /> 대응되는 IP 주소도 구했으니, 서버는 그 값을 클라이언트 측에 전송해 주는 것으로 모든 임무를 끝마칠 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // ============= 서버 측 프로그램 ============= private static void StartListener() { // ... 생략 ... while (!done) { byte[] bytes = listener.Receive(ref <span style='color: blue; font-weight: bold'>groupEP</span>); string txt = FindUdpEndpoint(groupEP); // UDP 브로드캐스팅을 발생시킨 클라이언트 측으로 맞대응되는 IP 주소를 전송 byte[] buffer = Encoding.UTF8.GetBytes(txt); listener.Send(buffer, buffer.Length, <span style='color: blue; font-weight: bold'>groupEP</span>); } // ... 생략 ... } </pre> <br /> 그럼, 클라이언트는 어떻게 응답을 수신하고 있어야 할까요? 단순하게 ReceiveFrom을 호출해도 되지만, 서비스로부터의 응답이 안 오는 경우도 발생할 수 있으므로 비동기 호출을 하는 것이 좋습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // ============= 클라이언트 측 프로그램 ============= static void Main(string[] args) { // ... 생략 ... s.SendTo(sendbuf, targetEndPoint); var arg = new SocketAsyncEventArgs(); arg.Completed += ReceiveAsync_Completed; arg.SetBuffer(new byte[4096], 0, 4096); // 비동기 방식의 수신 메서드 호출 s.ReceiveAsync(arg); Console.ReadLine(); } static void ReceiveAsync_Completed(object sender, SocketAsyncEventArgs e) { if (e.Buffer.Length == 0) { return; } // 수신이 완료되었을 때 호출되는 메서드 string txt = Encoding.UTF8.GetString(e.Buffer); Console.WriteLine("Echo from : " + txt.TrimEnd('\0')); } </pre> <br /> 결과적으로, 사용자는 IP 주소를 입력할 필요가 없어졌으니 프로그램 사용이 보다 더 편해지게 되었습니다. ^^<br /> <br /> (<a target='tab' href='http://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=792&boardid=331301885'>첨부한 파일은 예제 프로젝트</a>를 담고 있습니다.)<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1375
(왼쪽의 숫자를 입력해야 합니다.)