Linux下编程获取本地IP地址的常见方法
转载于:http://blog.csdn.net/k346k346/article/details/48231933
在进行linux网络编程时,经常用到本机IP地址。本文罗列一下常见方法,以备不时之需。
获取本机IP地址,是一个相当灵活的操作,原因是网络地址的设置非常灵活而且都是允许用户进行个性化设置的。比如一台计算机上可以有多块物理网卡或者虚拟网卡,一个网卡上可以绑定多个IP地址,用户可以为网卡设置别名,可以重命名网卡。用户计算机所在网络拓扑结构未知,主机名设置是一个可选项,并且同样可以为一个计算机绑定多个主机名等,这些信息都会有影响。脱离了网络连接,单独的网络地址没有任何意义。编程中遇到必须获取计算机IP的场景,应该考虑将这一选项放到配置文件中,由用户自己来设置。
参考网络和书本,编程获取本机IP地址大约有以下几种方法。
方法一:ioctl()获取本地IP地址 Linux 下 可以使用ioctl()函数以及结构体 struct ifreq和结构体struct ifconf来获取网络接口的各种信息。
具体过程是先通过ictol获取本地的所有接口信息,存放到ifconf结构中,再从其中取出每个ifreq表示的ip信息(一般每个网卡对应一个IP地址,如:”eth0…、eth1…”)。
先了解结构体 struct ifreq和结构体struct ifconf:
//ifconf通常是用来保存所有接口信息的
//if.h
struct ifconf
{
int ifc_len; /* size of buffer */
union
{
char *ifcu_buf; /*input from user->kernel*/
struct ifreq *ifcu_req; /* return from kernel->user*/
} ifc_ifcu;
};
#define ifc_buf ifc_ifcu.ifcu_buf /*buffer address */
#define ifc_req ifc_ifcu.ifcu_req /*array of structures*/
//ifreq用来保存某个接口的信息
//if.h
struct ifreq {
char ifr_name[IFNAMSIZ];
union {
struct sockaddr ifru_addr;
struct sockaddr ifru_dstaddr;
struct sockaddr ifru_broadaddr;
short ifru_flags;
int ifru_metric;
caddr_t ifru_data;
} ifr_ifru;
};
#define ifr_addr ifr_ifru.ifru_addr
#define ifr_dstaddr ifr_ifru.ifru_dstaddr
#define ifr_broadaddr ifr_ifru.ifru_broadaddr
如果本机的IP地址绑定在第一块网卡上,指定网卡名称,无需获取所有网卡的信息,即可获取,见如下函数:
string getLocalIP(){
int inet_sock;
struct ifreq ifr;
char ip[32]={NULL};
inet_sock = socket(AF_INET, SOCK_DGRAM, 0);
strcpy(ifr.ifr_name, "eth0");
ioctl(inet_sock, SIOCGIFADDR, &ifr);
strcpy(ip, inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
return string(ip);
}
如果想获取所有网络接口信息,参见如下代码:
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char* argv[])
{
int sockfd;
struct ifconf ifconf;
struct ifreq *ifreq;
char buf[512];//缓冲区
//初始化ifconf
ifconf.ifc_len =512;
ifconf.ifc_buf = buf;
if ((sockfd =socket(AF_INET,SOCK_DGRAM,0))<0)
{
perror("socket" );
exit(1);
}
ioctl(sockfd, SIOCGIFCONF, &ifconf); //获取所有接口信息
//接下来一个一个的获取IP地址
ifreq = (struct ifreq*)ifconf.ifc_buf;
printf("ifconf.ifc_len:%d\n",ifconf.ifc_len);
printf("sizeof (struct ifreq):%d\n",sizeof (struct ifreq));
for (int i=(ifconf.ifc_len/sizeof (struct ifreq)); i>0; i--)
{
if(ifreq->ifr_flags == AF_INET){ //for ipv4
printf("name =[%s]\n" , ifreq->ifr_name);
printf("local addr = [%s]\n" ,inet_ntoa(((struct sockaddr_in*)&(ifreq->ifr_addr))->sin_addr));
ifreq++;
}
}
getchar();//system("pause");//not used in linux
return 0;
}
运行输出:
方法二:getsockname()获取本地IP地址 如果建立TCP连接的情况下,可以通过getsockname和getpeername函数来获取本地和对端的IP和端口号。前提是已经与对方建立了连接。 参考代码如下:
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
int main(int argc, char* argv[])
{
int fd=socket(AF_INET,SOCK_STREAM,0);//创建本地sock描述符
struct sockaddr_in servaddr,localaddr,peeraddr;
socklen_t len;
//初始化服务端地址并连接
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family=AF_INET;
servaddr.sin_port=htons(PORT);//PORT自己指定
char* servIP=”177.56.23.4”;//服务端IP
inet_pton(AF_INET,servIP,&servaddr.sin_addr);
if(connect(fd,(struct sockaddr*)&servaddr,sizeof(servaddr))<0)
{
cerr<<"connect error"<<endl;
return -1;
}
char buf[30]="";
bzero(&localaddr,sizeof(localaddr));
getsockname(fd,(struct sockaddr*)&localaddr,&len); //获取本地信息
cout<<"local ip is "<<inet_ntop(AF_INET,&localaddr.sin_addr,buf,sizeof(buf))<<"local port is"<<ntohs(localaddr.sin_port)<<endl;
bzero(&peeraddr,sizeof(peeraddr));
getpeername(fd,(struct sockaddr*)&peeraddr,&len); //获取对端信息
cout<<"peer ip is "<< inet_ntop(AF_INET,&peeraddr.sin_addr,buf,sizeof(buf))<<"peer port is "<<ntohs(peeraddr.sin_port)<<endl;
return 1;
}
}
下面两种方法,都是通过主机名称来获取主机的IP地址,在获取本地IP地址时,一般都是回环地址,但可以有效的根据主机名称获取网络中的主机的IP地址,如通过域名获取域名对应的IP地址。
要想精确的获取某块网卡绑定的IP地址,请根据ioctl()和接口名称(如eth0)来获取,具体实现见上文。
方法三:getaddrinfo()获取本地IP地址 注意,getaddrinfo()可以完成网络主机中主机名和服务名到地址的映射,但是一般不能用来获取本地IP地址,当它用来获取本地IP地址时,返回的一般是127.0.0.1本地回环地址。 所需头文件:
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
用例如下:
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char* argv[])
{
char host_name[128]={NULL};
gethostname(host_name, sizeof(host_name));//获取本地主机名称
printf("host_name:%s\n",host_name);
struct addrinfo *ailist=NULL,*aip=NULL;
struct sockaddr_in *saddr;
char *addr;
int ret=getaddrinfo(host_name,NULL,NULL,&ailist);
for(aip=ailist; aip!=NULL; aip=aip->ai_next)
{
if(aip->ai_family==AF_INET)
{
saddr=(struct sockaddr_in*)aip->ai_addr;
addr=inet_ntoa(saddr->sin_addr);
}
printf("addr:%s\n",addr);
}
printf("\n-----------------baidu host info-------------------\n");
getaddrinfo("www.baidu.com","http",NULL,&ailist);
for(aip=ailist; aip!=NULL; aip=aip->ai_next)
{
if(aip->ai_family==AF_INET)
{
saddr=(struct sockaddr_in*)aip->ai_addr;
addr=inet_ntoa(saddr->sin_addr);
}
printf("baidu addr:%s\n",addr);
}
getchar();
return 0;
}
使用gcc编译此程序会出现error: dereferencing pointer to incomplete type的错误,使用g++编译通过,程序输出:
方法四:gethostname()获取本地IP地址 gethostname()和getaddrinfo()的功能类似,一般用于通过主机名或者服务名,比如域名来获取主机的IP地址。但是要想获取本地IP地址的时候,一般获取的是回环地址127.0.0.1。
string getLocalIP(char* local_ip) {
// 获取本地IP时,一般都是127.0.0.1
char host_name[128]="";
struct hostent *host_ent;
gethostname(host_name, sizeof(host_name));
host_ent = gethostbyname(host_name);
const char* first_ip = inet_ntoa(*(struct in_addr*)(host_ent->h_addr_list[0]));
memcpy(local_ip, first_ip, 16);
return string(host_name);
}
注意,主机的地址是一个列表的形式,原因是当一个主机有多个网络接口时,及多块网卡或者一个网卡绑定多个IP地址时,自然就有多个IP地址。以上代码获取的是根据主机名称得到的第一个IP地址。
参考文献 [1]http://blog.sina.com.cn/s/blog_9df3961501010hzj.html [2]http://blog.csdn.net/darennet/article/details/9338819
Linux下编程获取本地IP地址的常见方法的更多相关文章
- Linux C 网络编程 - 获取本地 ip 地址,mac,通过域名获取对应的 ip
获取本地 ip 地址,mac,通过域名获取对应的 ip, 是网络编程可能遇到的比较常见的操作了,所以总结如下(封装了3个函数), 直接上代码: #include <stdio.h> #in ...
- 获取本地ip地址 C#
与ipconfig获取的所有信息一致的方法: private void GetIp() { System.Diagnostics.Process cmdp= new System.Diagnostic ...
- Linux编程获取本地IP
#include <stdio.h> #include <sys/types.h> #include <ifaddrs.h> #include <netine ...
- 获取本地IP地址信息
2012-06-05 /// <summary> /// 获取本地IP地址信息 /// </summary> void G ...
- C# — 动态获取本地IP地址及可用端口
1.在VS中动态获取本地IP地址,代码如下: 2.获取本机的可用端口以及已使用的端口:
- .net获取本地ip地址
整理代码,.net获取本地ip地址,代码如下: string name = Dns.GetHostName(); IPHostEntry IpEntry = Dns.GetHostEntry(name ...
- 获取本地IP地址的vc代码
作者:朱金灿 来源:http://blog.csdn.net/clever101 获取本地IP地址有两种做法.一种是使用gethostname函数,代码如下: bool CSocketComm::Ge ...
- .net core获取本地Ip地址的方法
笔记: /// <summary> /// 获取本地Ip地址 /// </summary> /// <returns></returns> public ...
- python获取本地ip地址的方法
#_*_coding:utf8_*_ #以下两种方法可以在ubuntu下或者windows下获得本地的IP地址 import socket # 方法一 localIP = socket.gethost ...
随机推荐
- flask框架(十): 闪现
一:闪现flash基本用法 # -*- coding: utf-8 -*- # @Author : Felix Wang # @time : 2018/7/5 9:34 from flask impo ...
- CUDA-F-1-1-异构计算-CUDA
开篇废话 成熟与智慧其实和年龄相关,但绝不是完全由年龄决定,少年老成的人肯定是存在的,不是长得老,而是心态成熟,当然大多数老年人其实有些事情思考起来还是老原则,所以他们有时候做事没那么周到,所以一个人 ...
- [Python] 等号赋值, copy, deepcopy的区别
参考链接: 1. 介绍python中的可变类型与不可变类型:https://blog.csdn.net/answer3lin/article/details/86430074 (也可以参考转载博客 P ...
- springboot 2.2.0 SNAPSHOT 解决 repositories.repository.id must be unique 的问题
如果打包 jar 也报错了 ,那也是这个的原因,注释掉即可 <!-- 这个仓库必须注释掉 否则打包 war 的时候 , 会报错 'repositories.repository.id' must ...
- TCP输入 之 快速路径和慢速路径
概述 快速路径:用于处理预期的,理想情况下的数据段,在这种情况下,不会对一些边缘情形进行检测,进而达到快速处理的目的: 慢速路径:用于处理那些非预期的,非理想情况下的数据段,即不满足快速路径的情况下数 ...
- vmalloc详解
vmalloc是一个接口函数, 内核代码使用它来分配在虚拟内存中连续但在物理内存中不一定连续的内存. 只需要一个参数,以字节为单位. 使用vmalloc的最著名的实例是内核对模块的实现. 因为模块可能 ...
- LC 890. Find and Replace Pattern
You have a list of words and a pattern, and you want to know which words in words matches the patter ...
- 使用谷歌提供的SwipeRefreshLayout下拉控件,并自定义实现下拉加载的功能
package com.loaderman.swiperefreshdemo; import android.os.Bundle; import android.os.Handler; import ...
- .NET GC简单理解
内存分配 计算对象大小. 添加对象指针和同步索引块. 从内存指针处开始,分配对象内存. 问题:内存不能无限制增长. 垃圾回收 从应用程序实例出发,标记所有的引用对象. 将标记对象移动到低地址端,修正实 ...
- SQL学习(一)相关基础知识
RDBMS基础知识 1.数据库是按照数据结构来组织.存储和管理数据的仓库:数据库是一些关联表的集合. 2.数据表是数据的矩阵,在一个数据库中的表看起来像一个简单的电子表格. 3.列:一列包含了相同的数 ...