ネットワーク プログラミングを行う場合Linux
、多くの場合、マシンのアドレスを取得する必要がありますIP
。構成ファイルの通常の読み取りに加えて、この記事では、個人に知られている一般的に使用されるいくつかのプログラミング方法を参考のためにリストします。間違いがあればご指摘ください。 。
方法 1: ioctl() を使用してローカル IP アドレスを取得する
Linux
以下では、ioctl()
関数、構造体struct ifreq
、および構造体を使用してstruct ifconf
、ネットワーク インターフェイスに関するさまざまな情報を取得できます。具体的な処理としては、ictol
すべてのローカルインターフェースの情報を取得してifconf
構造体に保存し、ifreq
そこからそれぞれが表すインターフェース情報を抽出します。
本機のアドレスが最初のネットワークカードにバインドされている場合はIP
、すべてのネットワークカードの情報を取得しなくても、ネットワークカード名を指定するだけで取得できます。以下の関数を参照してください。
int get_localip(const char * eth_name, char *local_ip_addr)
{
int ret = -1;
register int fd;
struct ifreq ifr;
if (local_ip_addr == NULL || eth_name == NULL)
{
return ret;
}
if ((fd=socket(AF_INET, SOCK_DGRAM, 0)) > 0)
{
strcpy(ifr.ifr_name, eth_name);
if (!(ioctl(fd, SIOCGIFADDR, &ifr)))
{
ret = 0;
strcpy(local_ip_addr, inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
}
}
if (fd > 0)
{
close(fd);
}
return ret;
}
すべてのネットワーク インターフェイス情報を取得する場合のサンプル コードは次のとおりです。
#include <stdio.h>
#include <net/if.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
int get_localip(const char * eth_name, char *local_ip_addr)
{
int ret = -1;
register int fd, intrface;
struct ifreq ifr[32];
struct ifconf ifc;
if (local_ip_addr == NULL || eth_name == NULL)
{
return ret;
}
if ((fd=socket(AF_INET, SOCK_DGRAM, 0)) > 0)
{
ifc.ifc_len = sizeof ifr;
ifc.ifc_buf = (caddr_t)ifr;
if (!ioctl(fd, SIOCGIFCONF, (char*)&ifc)) //获取所有接口信息
{
intrface = ifc.ifc_len / sizeof(struct ifreq);
while (intrface-- > 0)
{
//Get IP Address
if (!(ioctl(fd, SIOCGIFADDR, (char*)&ifr[intrface])))
{
if(strcmp(eth_name, ifr[intrface].ifr_name) == 0)
{
ret = 0;
sprintf(local_ip_addr, "%s", inet_ntoa(((struct sockaddr_in*)(&ifr[intrface].ifr_addr))->sin_addr));
break;
}
}
}
}
}
if (fd > 0)
{
close(fd);
}
return ret;
}
int main(int argc, const char **argv)
{
int ret;
char local_ip[20] = {
0};
ret = get_localip("eth0", local_ip);
if (ret == 0)
{
printf("local ip:%s\n", local_ip);
}
else
{
printf("get local ip failure\n");
}
return 0;
}
方法 2:getsockname() によるローカル IP アドレスの取得
getsockname()
バインドまたは接続されたソケットのローカル アドレスを取得するために使用されます。ソケットINADDR_ANY
が でバインドされている場合、つまり、ソケットは、呼び出しconnect()
またはaccept()
接続しない限り、現時点では任意のホストのアドレスを使用できます。それ以外の場合は、ホスト アドレスに関する情報はgetsockname()
返されません。IP
サンプルコード:
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define PORT 80
#define SERVER_IP "192.168.10.31"
int main(int argc, const char **argv)
{
int ret = -1;
socklen_t len;
char buf[30] = {
0};
struct sockaddr_in server_addr, local_addr;
int fd = socket(AF_INET, SOCK_STREAM, 0);
//int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd <= 0)
{
printf("fail to creat socket\n");
return -1;
}
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
if(connect(fd, (struct sockaddr*)&server_addr, sizeof(server_addr))<0)
{
printf("connect error!!!\n");
goto end;
}
len = sizeof(local_addr);
memset(&local_addr, 0, sizeof(local_addr));
ret = getsockname(fd, (struct sockaddr*)&local_addr, &len);
if (ret == 0)
{
printf("local ip is %s, local port is %d\n", inet_ntop(AF_INET, &local_addr.sin_addr, buf, sizeof(buf)), ntohs(local_addr.sin_port));
}
else
{
printf("getsockname failed, error=%d\n", errno);
}
end:
if (fd)
{
close(fd);
}
return ret;
}
方法 3: getaddrinfo() でローカル IP アドレスを取得する
getaddrinfo()
ホスト名とサービス名からネットワーク ホスト内のアドレスへのマッピングを完了できますが、一般にローカル アドレスの取得には使用できません。ローカルアドレスIP
の取得に使用される場合IP
、通常は127.0.0.1
ローカル ループバック アドレスが返されます。この関数はそれのみをサポートしますIPv4
。
サンプルコード:
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>
// 获取本地IP时,一般都是127.0.0.1
int main(int argc, const char **argv)
{
int ret;
char host_name[128] = {
0};
struct addrinfo *res, *cur;
struct sockaddr_in *addr;
if (gethostname(host_name, sizeof(host_name)) < 0)
{
printf("gethostname error\n");
return -1;
}
ret = getaddrinfo(host_name, NULL, NULL, &res);
if (ret != 0)
{
printf("Error: error in getaddrinfo on hostname: %s\n", gai_strerror(ret));
return -1;
}
for(cur = res; cur != NULL; cur = cur->ai_next)
{
if(cur->ai_family == AF_INET)
{
addr = (struct sockaddr_in*)cur->ai_addr;
printf("local ip:%s\n", inet_ntoa(addr->sin_addr));
}
//char host[1024] = {0};
//ret = getnameinfo(cur->ai_addr, cur->ai_addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST);
//if(ret != 0)
//{
// printf("getnameinfo: %s\n", gai_strerror(ret));
//}
//else
//{
// printf("ip: %s\n", host);
//}
}
freeaddrinfo(res);
return 0;
}
方法 4: gethostbyname() でローカル IP アドレスを取得する
gethostbyname()
getaddrinfo()
の機能と同様に、これは通常、ホスト名またはドメイン名などのサービス名を通じてホストのアドレスを取得するために使用されますIP
。ただしIP
、ローカル アドレスを取得する場合は、通常、ループバック アドレスを取得します127.0.0.1
。
サンプルコード:
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>
// 获取本地IP时,一般都是127.0.0.1
int main(int argc, const char **argv)
{
int i = 0;
char host_name[128] = {
0};
struct hostent *hptr;
if (gethostname(host_name, sizeof(host_name)) < 0)
{
printf("gethostname error\n");
return -1;
}
if ((hptr=gethostbyname(host_name)) == NULL)
{
printf("gethostbyname error\n");
return -1;
}
while(hptr->h_addr_list[i] != NULL)
{
printf("hostname: %s\n", hptr->h_name);
printf(" ip: %s\n", inet_ntoa(*(struct in_addr*)hptr->h_addr_list[i]));
i++;
}
return 0;
}
方法 5: getifaddrs() を通じてローカル IP アドレスを取得する
コードの由来StackOverflow
: http://stackoverflow.com/questions/212528/linux-c-get-the-ip-address-of-local-computer
コードでINET_ADDRSTRLEN
は、ヘッダー ファイルINET6_ADDRSTRLEN
でマクロ変数が定義されています。netinet/in.h
// FILE: netinet/in.h
#define INET_ADDRSTRLEN 16 /* for IPv4 dotted-decimal */
#define INET6_ADDRSTRLEN 46 /* for IPv6 hex string */
サンプルコード:
#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;
}
方法 6: Popen() を通じて ifconfig を呼び出してローカル IP アドレスを取得する
を使用してpopen()
パイプラインを構築し、パイプラインの一方の端でコマンドを実行しifconfig
、パイプラインの他方の端で受信したデータを読み取り、対応する分析を実行します。この方法は、shell
コマンドを実行し、正規表現と連携する必要がありますが、非効率的であり、通常は使用されません。そして、この方法は実際には設定に依存する傾向があり、その理由は使いやすいからです。
サンプルコード:
#include <stdio.h>
#include <stdlib.h>
#define ETH_NAME "ens33"
int main(int argc, const char *argv[])
{
FILE *fp;
char buf[256] = {
0};
char command[256] = {
0};
//char *fmt = "ifconfig %s|sed -n '2p'|sed -n 's#^.*dr:##gp'|sed -n 's#B.*$##gp'";
char *fmt = "ifconfig %s|grep 'inet addr'|awk '{ print $2}' | awk -F: '{print $2}'";
snprintf(command, sizeof(command), fmt, ETH_NAME);
if((fp = popen(command, "r")) == NULL)
{
perror("Fail to popen\n");
return -1;
}
while(fgets(buf, sizeof(buf), fp) != NULL)
{
printf("%s", buf);
}
pclose(fp);
return 0;
}
参考記事
[1] https://blog.csdn.net/bailyzheng/article/details/7489656
[2] https://blog.csdn.net/k346k346/article/details/48231933
[3] https://blog.csdn .net/zhongmushu/article/details/89944990