[질문]C언어 자신의 ip 알아볼려면(윈도에서)?

psycoder의 이미지

안녕하세요.
실력이 없어서 자꾸 질문만 드리네요. :oops:
윈도에서 C언어로 프로그램을 하나 만들고 있는데요..
자신의 ip를 얻어야 하는데 어떻게 해야하는지 모르겠네요.
dns에 등록되지 않은 컴퓨터이므로 gethostbyname() 같은건 사용할수 없습니다.
5시간째 검색하고 책 찾아보고 코딩해보고 하는데 도저히 모르겠어서 질문 올립니다.
예제 소스나 힌트좀 부탁드립니다.
참, 윈9x/nt/2000/xp/2003 모두 지원해야합니다.
그럼 좋은 하루 되세요. :)

Rica의 이미지

외부의 다른 서버에 접속한 뒤 아래 코드를 수행하면 자신의 주소를 얻어올 수 있습니다. connect의 오버헤드가 있지만 확실한 결과를 얻습니다.
(공유기 등을 통하는 경우, 로컬 IP만 검색하면 192.168.0.1 같은 것들만 잡히는 경우가 있더군요. connect 없이 IP주소를 제대로 얻는 방법이 있으면 알려주시길 바랍니다.)

	SOCKADDR_IN sockAddr;
	memset(&sockAddr, 0, sizeof(sockAddr));

	int nSockAddrLen = sizeof(sockAddr);
	BOOL bResult = (getsockname(hSocket,(SOCKADDR*)&sockAddr,&nSockAddrLen) == 0);
	if( bResult )
	{
		socketPort = ntohs(sockAddr.sin_port);
		socketAddress = inet_ntoa(sockAddr.sin_addr);
		return true;
	}
	else
		return false;

위 코드와는 별개로, connect 없이 로컬의 모든 아이피 주소를 받아오는 코드입니다:

		vector<string> addresses;

		char szHostname[100];
		HOSTENT* pHostEnt;
		int nAdapter = 0;

		gethostname( szHostname, sizeof( szHostname ));
		pHostEnt = gethostbyname( szHostname );

		addresses.clear();
		
		while ( pHostEnt->h_addr_list[nAdapter] )
		{
			addresses.push_back( inet_ntoa(*(struct in_addr*)pHostEnt->h_addr_list[nAdapter]) );
			nAdapter++;
		};

한 개 더 있었는데 어디갔는지 모르겠네요 :oops:

서지훈의 이미지

#include <netinet/in.h>
#include <sys/utsname.h>
#include <netdb.h>

/*
 *  Description : Current localhost IP
 *  Argument    : addrtype  - type of address (INET4 or INET6)
 *  Return      : the hostent structure or a NULL pointer
 */
char **my_addrs(int *addrtype)
{
    struct hostent  *hptr;
    struct utsname  myname;


    if (uname(&myname) < 0)
        return NULL;

    if ((hptr = gethostbyname(myname.nodename)) == NULL)
        return NULL;

    *addrtype = hptr->h_addrtype;


    return (hptr->h_addr_list);
}

이거 즉빵입니다.

#include <com.h> <C2H5OH.h> <woman.h>
do { if (com) hacking(); if (money) drinking(); if (women) loving(); } while (1);

Rica의 이미지

Quote:
#include <netinet/in.h>
#include <sys/utsname.h>
#include <netdb.h>

윈도우 코드가 아니군요. 8)

psycoder의 이미지

답변 감사합니다. :D

Rica님 갈켜주신데로 connect()후 getsockname() 을 해주니 ip를 알수 있네요.
근데 역시 말씀하신데로 connect를 해야 한다는 단점이 있네요.

윈도에서 자체 지원해주는 api(이를테면 랜카드의 ip정보를 알아오는)가 있을듯 한데..
그간 바빠서 손을 못데고 있었는데 좀 알아봐야 겠군요.

madkoala의 이미지

NT를 지원하지 않아도 괜찮다면 이런 것도 괜찮습니다.

DWORD				dwStatus;
	ULONG				ulSizeAdapterInfo = 0;
	IP_ADAPTER_INFO*	pAdapterInfo = NULL;
	IP_ADAPTER_INFO*	pOriginalPtr = NULL;
	
	dwStatus = GetAdaptersInfo(pAdapterInfo, &ulSizeAdapterInfo);
	
	//***********************************************************************
	//버퍼 오버 플로우 일때 ulSizeAdapterInfo 크기로 메모리를 할당하고 
	//다시 GetAdaptersInfo를 호출한다.
	if(dwStatus == ERROR_BUFFER_OVERFLOW) {
		pAdapterInfo = (PIP_ADAPTER_INFO)malloc(ulSizeAdapterInfo);
		dwStatus = GetAdaptersInfo(pAdapterInfo,&ulSizeAdapterInfo);
	}
	
	char Gageway_Addr[16];
	while(1) {
		if(strlen(pAdapterInfo->GatewayList.IpAddress.String) > 0) {
			memset(Gageway_Addr, 0x00, 16);
			for(int x=0; x<16; x++) {
				Gageway_Addr[x] = pAdapterInfo->IpAddressList.IpAddress.String[x];
			}
			
			break;
		}
		
		if(pAdapterInfo->Next != NULL) {
			pAdapterInfo = pAdapterInfo->Next;
		}
	}
	
	strRoutedLocalIP = Gageway_Addr;

또 이런 방법도 있죠.

std::string			strRoutedLocalIP = "";

	PMIB_IPADDRTABLE	pIPAddrTable;
	DWORD				dwSize = 0;
	DWORD				dwRetVal = 0;

	pIPAddrTable = (MIB_IPADDRTABLE*) malloc( sizeof( MIB_IPADDRTABLE) );

	// Make an initial call to GetIpAddrTable to get the
	// necessary size into the dwSize variable
	if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
		GlobalFree( pIPAddrTable );
		pIPAddrTable = (MIB_IPADDRTABLE *) malloc ( dwSize );
	}

	// Make a second call to GetIpAddrTable to get the
	// actual data we want
	dwRetVal = GetIpAddrTable(pIPAddrTable, &dwSize, 0);
	if(dwRetVal == NO_ERROR) {
		DWORD			dwIndex = 0;
		struct in_addr	in;
		char*			pstrIP = NULL;

		for(dwIndex = 0; dwIndex < pIPAddrTable->dwNumEntries; dwIndex++) {
			in.s_addr = pIPAddrTable->table[dwIndex].dwAddr;
			pstrIP = inet_ntoa(in);
			if(strstr(pstrIP, "127.0.0.1") != NULL ||
			   strstr(pstrIP, "192.168.") != NULL ||
			   strstr(pstrIP, "169.254.") != NULL ||
			   strstr(pstrIP, "0.0.0.0") != NULL) {
				continue;
			}

			strRoutedLocalIP = pstrIP;
			return strRoutedLocalIP;
		}
	}

	strRoutedLocalIP = "";
	return strRoutedLocalIP;

플랫폼에 상관없는 방법이라면 이런 것도 있구요.

char		ac[80];
	std::string	strLocalIP = "";
	DWORD		dwErr;
	
	memset(ac, 0x00, 80);
	if(gethostname(ac, 80) == SOCKET_ERROR) {
		dwErr = GetLastError();
		_snprintf(ac, 80, "%d", dwErr);
		
		return strLocalIP;
	}

	struct hostent *phe = gethostbyname(ac);
	if(!phe) {
		return strLocalIP;
	} else {
		struct in_addr addr;
		memcpy(&addr, phe->h_addr_list[0], sizeof(struct in_addr));
		strLocalIP = inet_ntoa(addr);
	}

	return strLocalIP;
mach의 이미지

좋은 답변들이 많이 나왔습니다.
iphlpapi.dll(*.h)에 있는 함수들에 대해 검토해 보시지요.

------------------ P.S. --------------
지식은 오픈해서 검증받아야 산지식이된다고 동네 아저씨가 그러더라.

Testors의 이미지

참고..

1.
gethostbyname() 등의 콜을 사용하면..
/etc/hosts 혹은 DNS 설정에 따라 뜻하지 않은 결과를 얻을 수 있을것 같습니다.

2.
서지훈님의 예제로는..
네트웍 인터페이스 여러개이고,
운나쁘게 첫번째 인터페이스가 정상이 아닐경우.. 원치 않는 결과를 얻을 것 같군요.
(NIC 두개가 꽃혀있고 첫번째것이 그냥 꽃혀있기만한, 쓰래기 IP 를 가진 경우)

3. '자신의 IP' 란것은 여러개일수 있습니다. 가령 PC 에 모뎀과, 무선랜카드와, 일반 랜카드가 꽃혀있다면 IP 가 3개일수 있는데요..
'보통 외부 네트웍 접속에 사용되는 IP' 를 원하신 거라면..
가장 쉬운 방법은 connect() 때려보는 것이겠구요,
그게 아니라면 NIC 의 IP 리스트 얻어서 default gateway 와 같은 subnet 에 속한 녀석으로 고르는게 괜찮지 않을까 생각되지만... 과연 ;

gurugio의 이미지

혹시 자기가 가진 여러개의 IP중에

외부, 즉 인터넷에 접속된 IP를 알아내는 방법은 어떤게 있을까요?

connect를 해보려니 마땅히 접속할 곳도 애매하고

그냥 자체적으로 알아낼 수 없을까요?

ioctlsocket을 써야할까요?

리눅스에서는 아는데 윈도우즈에서는 잘 모르겠습니다.

맹고이의 이미지

이미 다 나온 이야기이지만...
예전에 정리해둔게 있어서...

http://www.singlenote.net/wiki/wiki.php/ifconfigExample

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.