기기의 IP 주소를 가져옵니다.
이 질문은 이전에 요청한 로컬 컴퓨터의 IP 주소에 대한 질문과 거의 동일 합니다 . 그러나 Linux 머신 의 IP 주소를 찾아야합니다 .
그래서 : C ++ 에서 프로그래밍 방식으로 애플리케이션이 실행중인 Linux의 IP 주소를 어떻게 감지 합니까? 서버에는 최소한 두 개의 IP 주소가 하나의 특정 주소가 필요합니다 (주어진 네트워크에있는 주소 (공용 주소)).
수행하는 간단한 기능이 확신합니다. 그러나 어디에서?
좀 더 명확하게 광고 :
- 서버는 분명히 "localhost": 127.0.0.1을 번거 롭습니다.
- 서버에는 내부 (관리) IP 주소가 있습니다. 172.16.xx
- 서버에는 외부 (공용) IP 주소가 있습니다. : 80.190.xx
내 애플리케이션을 바인딩 할 외부 IP 주소를 찾아야합니다. 분명히 INADDR_ANY에 바인딩 할 수도 있습니다 (실제로 내가하는 일입니다). 그래도 공개 주소를 감지하고 싶습니다.
OS x에서 ioctl 솔루션이 문제가 있음을 발견했습니다 (POSIX에서 Linux와 유사해야 함). 그러나 getifaddress ()를 사용하면 똑같은 일을 쉽게 할 수 있습니다. os x 10.5에서 작동하며 아래에서 동일해야합니다.
아래에서 시스템의 모든 IPv4 주소를 인쇄하는 간단한 예제를 수행했습니다 (getifaddrs가 성공했는지 확인해야합니다. 즉, 0을 반환합니다).
IPv6 주소도 표시 업데이트했습니다.
#include <stdio.h>
#include <sys/types.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
int main (int argc, const char * argv[]) {
struct ifaddrs * ifAddrStruct=NULL;
struct ifaddrs * ifa=NULL;
void * tmpAddrPtr=NULL;
getifaddrs(&ifAddrStruct);
for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) {
if (!ifa->ifa_addr) {
continue;
}
if (ifa->ifa_addr->sa_family == AF_INET) { // check it is IP4
// is a valid IP4 Address
tmpAddrPtr=&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
char addressBuffer[INET_ADDRSTRLEN];
inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer);
} else if (ifa->ifa_addr->sa_family == AF_INET6) { // check it is IP6
// is a valid IP6 Address
tmpAddrPtr=&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
char addressBuffer[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer);
}
}
if (ifAddrStruct!=NULL) freeifaddrs(ifAddrStruct);
return 0;
}
- 소켓을 만듭니다.
- 행하다
ioctl(<socketfd>, SIOCGIFCONF, (struct ifconf)&buffer);
및 구조 /usr/include/linux/if.h
에 대한 정보를 기술 . 시스템에있는 각 인터페이스의 IP 주소를 제공해야합니다. 추가 ioctl에 읽어들입니다 .ifconf
ifreq
/usr/include/linux/sockios.h
나는 jjvainio의 대답을 좋아 합니다. Zan Lnyx가 말했듯이, 로컬 라우팅 테이블을 사용하여 특정 외부 호스트에 연결하는 데 스키마 인터페이스의 IP 주소를 찾습니다. 소켓 UDP 소켓을 사용하면 실제로 패킷을 보내지 제공 정보를 얻을 수 있습니다. 접근 방식을 사용하는 특정 외부 호스트를 선택해야합니다. 공용 IP가 트릭을 수행해야합니다. 이 목적을 위해 Google의 공용 DNS 서버 주소 8.8.8.8을 좋아하지만 다른 외부 호스트 IP를 선택하고 싶을 때 있습니다. 다음은 전체 접근 방식을 코드입니다.
void GetPrimaryIp(char* buffer, size_t buflen)
{
assert(buflen >= 16);
int sock = socket(AF_INET, SOCK_DGRAM, 0);
assert(sock != -1);
const char* kGoogleDnsIp = "8.8.8.8";
uint16_t kDnsPort = 53;
struct sockaddr_in serv;
memset(&serv, 0, sizeof(serv));
serv.sin_family = AF_INET;
serv.sin_addr.s_addr = inet_addr(kGoogleDnsIp);
serv.sin_port = htons(kDnsPort);
int err = connect(sock, (const sockaddr*) &serv, sizeof(serv));
assert(err != -1);
sockaddr_in name;
socklen_t namelen = sizeof(name);
err = getsockname(sock, (sockaddr*) &name, &namelen);
assert(err != -1);
const char* p = inet_ntop(AF_INET, &name.sin_addr, buffer, buflen);
assert(p);
close(sock);
}
알다시피 단일 "로컬 IP 주소"와 같은 것은 없습니다. 특정 호스트에 보낼 수있는 로컬 주소를 찾는 방법은 다음과 가변적입니다.
- UDP 소켓 만들기
- 소켓을 외부 주소 (결국 로컬 주소를받을 호스트)에 연결합니다.
- getsockname을 사용하여 로컬 주소를 가져옵니다.
이것은 유닉스의 많은 풍미에서 작업 할 수 있다는 장점이 있습니다. 그리고 모든 O / S에서 작업하도록 사소하게 수정할 수 있습니다. 위의 모든 솔루션은 달의 위상에 따라 컴파일러 오류를 제공합니다. 그것을하기위한 좋은 POSIX 방법이있는 순간 ... 이것을 사용하지 마십시오 (이 글이 쓰여진 당시에는 그렇지 않았습니다).
// ifconfig | perl -ne 'print "$1\n" if /inet addr:([\d.]+)/'
#include <stdlib.h>
int main() {
setenv("LANG","C",1);
FILE * fp = popen("ifconfig", "r");
if (fp) {
char *p=NULL, *e; size_t n;
while ((getline(&p, &n, fp) > 0) && p) {
if (p = strstr(p, "inet ")) {
p+=5;
if (p = strchr(p, ':')) {
++p;
if (e = strchr(p, ' ')) {
*e='\0';
printf("%s\n", p);
}
}
}
}
}
pclose(fp);
return 0;
}
귀하의 질문에 대한 확실한 정답이 없다고 생각합니다. 대신 원하는 것에 가까워지는 방법이 많이 있습니다. 따라서이를 수행하는 방법에 대한 몇 가지 힌트를 제공 할 것입니다.
시스템에 2 개 이상의 인터페이스 ( lo
하나로 계산)가있는 경우 올바른 인터페이스를 쉽게 자동 감지하는 데 문제가 있습니다. 이를 수행하는 방법에 대한 몇 가지 요리법이 있습니다.
예를 들어 문제는 호스트가 NAT 방화벽 뒤의 DMZ에있어 공용 IP를 일부 개인 IP로 변경하고 요청을 전달하는 경우입니다. 컴퓨터에 10 개의 인터페이스가있을 수 있지만 공용 인터페이스에는 하나만 해당됩니다.
방화벽이 소스 IP를 완전히 다른 것으로 변환하는 double-NAT에있는 경우 자동 감지조차 작동하지 않습니다. 따라서 기본 경로가 공용 인터페이스가있는 인터페이스로 연결되는지 확신 할 수 없습니다.
기본 경로를 통해 감지
이것이 자동 감지에 권장되는 방법입니다.
같은 뭔가가 ip r get 1.1.1.1
일반적으로 당신에게 기본 경로를 가진 인터페이스를 말한다.
좋아하는 스크립팅 / 프로그래밍 언어로 이것을 재현 strace ip r get 1.1.1.1
하려면 노란 벽돌 길을 사용 하고 따르십시오.
설정 /etc/hosts
당신이 통제력을 유지하고 싶다면 이것은 나의 추천입니다
다음 /etc/hosts
과 같이 항목을 만들 수 있습니다.
80.190.1.3 publicinterfaceip
그런 다음이 별칭 publicinterfaceip
을 사용 하여 공용 인터페이스를 참조 할 수 있습니다.
슬프게도
haproxy
IPv6로이 트릭을 익히지 않습니다.
환경 사용
이것은
/etc/hosts
당신이 그렇지 않은 경우에 대한 좋은 해결 방법입니다 .root
과 동일 /etc/hosts
. 그러나 이것을 위해 환경을 사용하십시오. /etc/profile
또는 ~/.profile
이것을 시도 할 수 있습니다 .
따라서 프로그램에 변수가 필요한 경우 MYPUBLICIP
다음과 같은 코드를 포함 할 수 있습니다.
#define MYPUBLICIPENVVAR "MYPUBLICIP"
const char *mypublicip = getenv(MYPUBLICIPENVVAR);
if (!mypublicip) { fprintf(stderr, "please set environment variable %s\n", MYPUBLICIPENVVAR); exit(3); }
따라서 다음 /path/to/your/script
과 같이 스크립트 / 프로그램을 호출 할 수 있습니다.
MYPUBLICIP=80.190.1.3 /path/to/your/script
이것은 crontab
.
모든 인터페이스를 열거하고 원하지 않는 인터페이스 제거
사용할 수 없다면 필사적 인 방법
ip
원하지 않는 것을 알고있는 경우 모든 인터페이스를 열거하고 모든 잘못된 인터페이스를 무시할 수 있습니다.
이 접근 방식에 대한 답은 이미 https://stackoverflow.com/a/265978/490291 인 것 같습니다 .
DLNA처럼
술에 빠져 죽으려는 술취한 남자의 길
네트워크의 모든 UPnP 게이트웨이를 열거 할 수 있으며이 방법으로 "외부"항목에 대한 적절한 경로를 찾을 수 있습니다. 기본 경로가 가리 키지 않는 경로에있을 수도 있습니다.
이에 대한 자세한 내용은 https://en.wikipedia.org/wiki/Internet_Gateway_Device_Protocol을 참조 하십시오.
이렇게하면 기본 경로가 다른 곳을 가리 키더라도 실제 공용 인터페이스가 어떤 것인지 좋은 인상을받을 수 있습니다.
더 있습니다
산이 선지자를 만나는 곳
IPv6 라우터는 올바른 IPv6 접두사를 제공하기 위해 스스로를 알립니다. 접두사를 보면 내부 IP 또는 글로벌 IP가 있는지에 대한 힌트를 얻을 수 있습니다.
IGMP 또는 IBGP 프레임을 수신하여 적합한 게이트웨이를 찾을 수 있습니다.
2 ^ 32 개 미만의 IP 주소가 있습니다. 따라서 LAN에서 모두 ping하는 데 오래 걸리지 않습니다. 이것은 귀하의 관점에서 인터넷의 대부분이 어디에 위치하는지에 대한 통계적 힌트를 제공합니다. 그러나 당신은 유명한 https://de.wikipedia.org/wiki/SQL_Slammer 보다 조금 더 현명해야합니다.
ICMP와 심지어 ARP는 네트워크 측 파대 정보에 대한 좋은 소스입니다. 그것은 당신에게도 도움이 될 것입니다.
이더넷 브로드 캐스트 주소를 사용하여 DHCP (DHCPv6 포함) 등과 같이 종종 도움이되는 모든 네트워크 인프라 장치에 연결할 수 있습니다.
이 추가 목록은 아마도 끝이없고 항상 불완전 할 것입니다. 모든 네트워크 장치 제조업체가 자신의 장치를 자동으로 감지하는 방법에 대한 새로운 보안 허점을 개발하고 있기 때문입니다. 이는 종종 존재하지 않는 공용 인터페이스를 감지하는 방법에 많은 도움이됩니다.
'그런가 말했다. 밖.
Steve Baker가 말한 것 외에도 netdevice (7) 매뉴얼 페이지 에서 SIOCGIFCONF ioctl에 대한 설명을 찾을 수 있습니다 .
호스트의 모든 IP 주소 목록이 있으면 애플리케이션 별 논리를 사용하여 원하지 않는 주소를 필터링하고 하나의 IP 주소가 남아 있기를 바랍니다.
하드 코딩하지 마십시오. 이것은 변경 될 수있는 일종의 것입니다. 많은 프로그램이 구성 파일을 읽고 그 내용을 수행하여 바인딩 할 대상을 파악합니다. 이렇게하면 나중에 프로그램이 공용 IP가 아닌 것에 바인딩해야하는 경우 그렇게 할 수 있습니다.
다음과 같이 쉽게 curl과 통합 할 수 있습니다 curl www.whatismyip.org
. 쉘에서 글로벌 IP를 얻을 수 있습니다. 일부 외부 서버에 의존하고 있지만 NAT 뒤에있는 경우 항상 그럴 것입니다.
질문에서 Linux를 지정했듯이 시스템의 IP 주소를 찾는 데 가장 좋아하는 기술은 netlink를 사용하는 것입니다. NETLINK_ROUTE 프로토콜의 넷 링크 소켓을 만들고 RTM_GETADDR을 보내면 사용 가능한 모든 IP 주소가 포함 된 메시지가 애플리케이션에 수신됩니다. 여기에 예가 제공 됩니다 .
메시지 처리의 일부를 간단히하기 위해 libmnl이 편리합니다. NETLINK_ROUTE의 다양한 옵션 (및 구문 분석 방법)에 대해 궁금한 점이 있다면 가장 좋은 소스는 iproute2 (특히 모니터 응용 프로그램) 의 소스 코드 와 커널의 수신 기능입니다. rtnetlink 의 man 페이지 에도 유용한 정보가 있습니다.
Linux 용 스크립트 솔루션은 http://www.damnsmalllinux.org/f/topic-3-23-17031-0.html 에서 찾을 수 있습니다 .
// Use a HTTP request to a well known server that echo's back the public IP address void GetPublicIP(CString & csIP) { // Initialize COM bool bInit = false; if (SUCCEEDED(CoInitialize(NULL))) { // COM was initialized bInit = true;
// Create a HTTP request object
MSXML2::IXMLHTTPRequestPtr HTTPRequest;
HRESULT hr = HTTPRequest.CreateInstance("MSXML2.XMLHTTP");
if (SUCCEEDED(hr))
{
// Build a request to a web site that returns the public IP address
VARIANT Async;
Async.vt = VT_BOOL;
Async.boolVal = VARIANT_FALSE;
CComBSTR ccbRequest = L"http://whatismyipaddress.com/";
// Open the request
if (SUCCEEDED(HTTPRequest->raw_open(L"GET",ccbRequest,Async)))
{
// Send the request
if (SUCCEEDED(HTTPRequest->raw_send()))
{
// Get the response
CString csRequest = HTTPRequest->GetresponseText();
// Parse the IP address
CString csMarker = "<!-- contact us before using a script to get your IP address -->";
int iPos = csRequest.Find(csMarker);
if (iPos == -1)
return;
iPos += csMarker.GetLength();
int iPos2 = csRequest.Find(csMarker,iPos);
if (iPos2 == -1)
return;
// Build the IP address
int nCount = iPos2 - iPos;
csIP = csRequest.Mid(iPos,nCount);
}
}
}
}
// Unitialize COM
if (bInit)
CoUninitialize();
}
참고 URL : https://stackoverflow.com/questions/212528/get-the-ip-address-of-the-machine
'IT' 카테고리의 다른 글
루비 배열을 함수 인수로 변환 (0) | 2020.09.05 |
---|---|
JQuery Ajax 요청의 진행 상황을 얻는 가장 중요한 방법은 무엇입니까? (0) | 2020.09.05 |
클래스가 클래스를 확장하고 인터페이스를 구현할 수 있습니까? (0) | 2020.09.05 |
Python에서 노드의 이스케이프 시퀀스 처리 (0) | 2020.09.04 |
float : left div를 가운데에 정렬? (0) | 2020.09.04 |