在LINUX下获取网卡信息需要用到IOCTL或者getifaddrs
而我在用getifaddrs的时候遇到了内存方面的问题
先看相关定义:
==========
函数定义:
/* Create a linked list of `struct ifaddrs' structures, one for each
network interface on the host machine. If successful, store the
list in *IFAP and return 0. On errors, return -1 and set `errno'.
The storage returned in *IFAP is allocated dynamically and can
only be properly freed by passing it to `freeifaddrs'. */
extern int getifaddrs (struct ifaddrs **__ifap) __THROW;
/* Reclaim the storage allocated by a previous `getifaddrs' call. */
extern void freeifaddrs (struct ifaddrs *__ifa) __THROW;
==============
此函数需要的结构体定义:
struct ifaddrs
{
struct ifaddrs *ifa_next; /* Pointer to the next structure. */
char *ifa_name; /* Name of this network interface. */
unsigned int ifa_flags; /* Flags as from SIOCGIFFLAGS ioctl. */
struct sockaddr *ifa_addr; /* Network address of this interface. */
struct sockaddr *ifa_netmask; /* Netmask of this interface. */
union
{
/* At most one of the following two is valid. If the IFF_BROADCAST
bit is set in `ifa_flags', then `ifa_broadaddr' is valid. If the
IFF_POINTOPOINT bit is set, then `ifa_dstaddr' is valid.
It is never the case that both these bits are set at once. */
struct sockaddr *ifu_broadaddr; /* Broadcast address of this interface. */
struct sockaddr *ifu_dstaddr; /* Point-to-point destination address. */
} ifa_ifu;
/* These very same macros are defined by <net/if.h> for `struct ifaddr'.
So if they are defined already, the existing definitions will be fine. */
# ifndef ifa_broadaddr
# define ifa_broadaddr ifa_ifu.ifu_broadaddr
# endif
# ifndef ifa_dstaddr
# define ifa_dstaddr ifa_ifu.ifu_dstaddr
# endif
void *ifa_data; /* Address-specific data (may be unused). */
};
=============
我在调用了getifaddrs()之后,正常地完成了需要的工作
但是最后如果用freeifaddrs,则出现运行时错误
*** glibc detected *** d: free(): invalid pointer: 0x0804a4d4 ***
======= Backtrace: =========
/lib/libc.so.6[0xb7eda911]
/lib/libc.so.6(__libc_free+0x84)[0xb7edbf84]
/lib/libc.so.6(freeifaddrs+0x1d)[0xb7f512dd]
d[0x8048989]
d[0x80486a5]
/lib/libc.so.6(__libc_start_main+0xdc)[0xb7e8c87c]
d[0x8048491]
======= Memory map: ========
08048000-08049000 r-xp 00000000 03:07 48637 /home/souldump/bin/d
08049000-0804a000 rw-p 00000000 03:07 48637 /home/souldump/bin/d
0804a000-0806b000 rw-p 0804a000 00:00 0 [heap]
b7d00000-b7d21000 rw-p b7d00000 00:00 0
b7d21000-b7e00000 ---p b7d21000 00:00 0
b7e76000-b7e77000 rw-p b7e76000 00:00 0
b7e77000-b7f90000 r-xp 00000000 03:05 16184 /lib/libc-2.4.so
b7f90000-b7f92000 r--p 00118000 03:05 16184 /lib/libc-2.4.so
b7f92000-b7f94000 rw-p 0011a000 03:05 16184 /lib/libc-2.4.so
b7f94000-b7f98000 rw-p b7f94000 00:00 0
b7fab000-b7fb5000 r-xp 00000000 03:05 20108 /lib/libgcc_s.so.1
b7fb5000-b7fb6000 rw-p 00009000 03:05 20108 /lib/libgcc_s.so.1
b7fb6000-b7fb7000 rw-p b7fb6000 00:00 0
b7fb7000-b7fd1000 r-xp 00000000 03:05 16177 /lib/ld-2.4.so
b7fd1000-b7fd3000 rw-p 00019000 03:05 16177 /lib/ld-2.4.so
bfb2b000-bfb41000 rw-p bfb2b000 00:00 0 [stack]
ffffe000-fffff000 ---p 00000000 00:00 0 [vdso]
实际上也有人出现相同问题:
http://p.g.yupoo.com/nph-proxy.cgi/000110A/http/www.linuxdby.com/bbs/viewthread.php=3ftid=3d10756
此人说:"这说明不是真正的链表,指针非法"
但是又没有进一步说明怎么解决
他干脆没有调用freeifaddrs,自然会内存泄漏.....
我去看了afaddrs.c
freeifaddrs的定义居然是:
void
freeifaddrs (struct ifaddrs *ifa)
{
free (ifa);
}
怎么样,很囧吧,明明在头文件里说"必须用freeifaddrs才能正确free..."
然后我看了一下getifaddrs的函数体
他在getifaddrs内部定义了一个结构
struct ifaddrs_storage
{
struct ifaddrs ifa;
union
{
/* Save space for the biggest of the four used sockaddr types and
avoid a lot of casts. */
struct sockaddr sa;
struct sockaddr_ll sl;
struct sockaddr_in s4;
struct sockaddr_in6 s6;
} addr, netmask, broadaddr;
char name[IF_NAMESIZE + 1];
};
然后把获取的各网卡信息一个个填充到此结构的struct ifaddrs ifa中,ifa的next值手动设置为下一个struct ifaddrs_storage中的ifa的地址...
这酒是所谓的"伪链表"吧?
这就是我无法正确free掉它的原因?
我究竟要怎么把它free掉?freeifaddrs一运行就运行时错误
LINUX取得本机IP的简单C程序
注意这里用了两个struct ifaddrs
//代码根据UNP和man手册编写
//适用于LINUX/BSD(FreeBSD, MacOS X)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ifaddrs.h>
int main(void)
{
struct ifaddrs *ifc, *ifc1;
char ip[64];
char nm[64];
if (0 != getifaddrs(&ifc)) return(-1);
ifc1 = ifc;
printf("Iface\tIP address\tNetmask\n");
for(; NULL != ifc; ifc = (*ifc).ifa_next) {
printf("%s", (*ifc).ifa_name);
if (NULL != (*ifc).ifa_addr) {
inet_ntop(AF_INET, &(((struct sockaddr_in*)((*ifc).ifa_addr))->sin_addr), ip, 64);
printf("\t%s", ip);
} else {
printf("\t\t");
}
if (NULL != (*ifc).ifa_netmask) {
inet_ntop(AF_INET, &(((struct sockaddr_in*)((*ifc).ifa_netmask))->sin_addr), nm, 64);
printf("\t%s", nm);
} else {
printf("\t\t");
}
printf("\n");
}
freeifaddrs(ifc1);
return(0);
}
谢谢!!!!和我原先的代码比较了一下:(省略了错误判断)
============原来的============
struct ifaddrs *ifap, *ifaphead, *ifaTmp;
getifaddrs(&ifap);
ifaphead = ifap;
while((ifapTmp = ifap) != NULL)
{
//实际任务代码
ifap = ifapTmp->ifa_next;
}
freeifaddrs(ifaphead);
=========修改后========
struct ifaddrs *ifap, *ifaphead;
getifaddrs(&ifap);
ifaphead = ifap;
while(ifap != NULL)
{
//实际任务代码
ifap = ifa_next;
}
freeifaddrs(ifaphead);
==================
仅仅是用了一个ifapTmp来代替ifap做事,区别仅此而已(而且我也忘了一开始为什么要用ifapTmp....)
但是最后都是用了freeifaddrs(ifaphead)啊,并没有传错指针啊????
中间的代码并没有对这段数据做任何修改啊.....
请指教一下,这唯一的区别为什么会造成我原先的代码freeifaddrs失败?谢谢!
ifaphead = ifap; //这里用ifaphead保存ifap指针地址
while((ifapTmp = ifap) != NULL)
{
ifap = ifapTmp->ifa_next; //这里修改了ifap的地址
}
freeifaddrs(ifaphead); //由于ifap的地址修改,所以ifaphead已经是无效指针。
********************************************************
struct socketaddr和struct socketaddr_in的区别
struct sockaddr,该类型是用来保存socket信息的:
struct sockaddr
{
unsigned short sa_family; /* 地址族, AF_xxx */
char sa_data[14]; /* 14 字节的协议地址 */
};
sa_family一般为AF_INET;
sa_data则包含该socket的IP地址和端口号。
另外还有一种结构类型:
struct sockaddr_in
{
short int sin_family; /* 地址族 */
unsigned short int sin_port; /* 端口号 */
struct in_addr sin_addr; /* IP地址 */
unsigned char sin_zero[8]; /* 填充0 以保持与struct sockaddr同样大小 */
};
sin_zero(它用来将sockaddr_in结构填充到与struct sockaddr同样的长度)
应该用bzero()或memset()函数将其置为零。
指向sockaddr_in 的指针和指向sockaddr的指针可以相互转换,这意味着如果一个函数所需参数类型是sockaddr时
,你可以在函数调用的时候将一个指向 sockaddr_in的指针转换为指向sockaddr的指针;或者相反。
sin_family通常被赋AF_INET;sin_port和 sin_addr应该转换成为网络字节优先顺序;而sin_addr则不需要转换。
分享到:
相关推荐
在Linux系统中,每个线程都有自己的内核态堆栈(kernel stack),这是操作系统为了处理中断和系统调用而为每个线程分配的一块内存区域。内核态堆栈中保存了线程执行系统调用或中断时的上下文信息,包括寄存器值、局部...
深入解析task_struct 结构体的几个字段
在Linux内核中,进程命名空间是实现容器和系统隔离的关键机制。进程命名空间允许不同的进程看到不同的进程ID视图,从而确保了进程间的独立性。`struct pid`和`struct task_struct`是内核中两个核心的数据结构,它们...
`getifaddrs`和`freeifaddrs`是两个在Unix-like系统中广泛使用的C语言函数,用于获取这些信息。但在Android平台上,由于其基于Linux内核但并非完全兼容,可能会遇到这两个函数未定义的引用问题。本文将详细解析这个...
在Python编程中,`struct`库是一个非常重要的模块,它提供了与C语言结构化数据类型进行转换的功能。在本项目"app_struct_pythonstruct_freeood_"中,主要关注的是如何使用`struct`库来处理IP地址的计算,特别是将一...
在C和C++中,`struct`的使用方式略有不同,特别是在与`typedef`关键字结合使用时。 1. `struct`定义: 在C语言中,定义一个结构体类型通常需要使用`typedef`关键字来创建一个别名,使得后续的声明更简洁。例如: ``...
在给定的压缩包文件中,我们有两个C语言源代码文件——`ptr_struct_file.c`和`buff_type_test.c`。这些文件主要涉及到Linux环境下的程序开发,利用C语言进行编程。在这里,我们将深入探讨这两个文件可能涉及的关键...
获取网络接口信息可能需要管理员权限,因此在运行Qt应用程序时,如果遇到权限问题,可能需要以管理员身份启动。此外,对于虚拟网卡,如桥接或NAT网络,它们的标识可能更复杂,需要额外的逻辑来识别。 总结来说,...
在 Linux 系统中,sched_domain 和 sched_group 层次结构的构建是通过对 CPU 的拓扑结构信息的获取和分析实现的。 首先,Linux 系统会从 cpuinfo_x86 结构中获取 CPU 的拓扑结构信息。cpuinfo_x86 结构包含了 CPU ...
在Linux环境下,可以使用`<sys/socket.h>`头文件中的`getifaddrs()`函数来获取网络接口的详细信息。这个函数会返回一个接口地址链表,每个元素包含了接口的名称、类型、地址等信息。通过遍历这个链表,我们可以获取...
在Linux操作系统中,`task_struct`是一个至关重要的数据结构,它代表了系统中的每一个进程。当我们谈论`task_struct`时,实际上是在讨论进程控制块(PCB,Process Control Block),这是理解和操纵进程行为的核心。 ...
在Linux中,可以使用`getifaddrs`函数来获取网络接口的信息,包括IP地址。这个函数会返回一个链表,包含了所有网络接口的详细信息。每个接口都有一个`struct ifaddrs`结构体,其中包含了接口名称、地址家族(IPv4或...
在Android系统中,获取本地设备的网络接口信息是开发中常见的需求,这通常涉及到网络编程和底层系统调用。`getifaddrs()`和`freeifaddrs()`这两个函数是Unix-like系统中用于获取和释放网络接口地址信息的C语言接口。...
在Python中,与C语言结构体打交道通常涉及到对内存布局的理解,因为不同平台的字节顺序和大小可能会有所不同。 `struct`模块的核心在于它的`pack`和`unpack`函数。`pack`函数用于将Python值转化为字节串,而`unpack...
C_C++中typedef_struct和struct的用法 在 C/C++ 中,struct 和 typedef struct 是两个常用的数据类型定义方式,它们之间有着微妙的区别。本文将详细介绍 struct 和 typedef struct 的用法,并通过实例代码演示其...
Linux内存管理是操作系统的核心部分,尤其在服务器和嵌入式系统中,高效的内存管理对于系统的性能和稳定性至关重要。本文将深入解析Linux内核中的内存描述符`mm_struct`,它是管理进程虚拟地址空间的关键数据结构。 ...
在单片机编程中,尤其是使用C语言进行开发时,结构体(Struct)是一种非常重要的数据...在学习过程中,读者需要关注结构体的内存对齐、存储开销以及访问效率等方面的问题,这些都是使用结构体时需要考虑的关键因素。
task_struct 数据结构是 Linux 操作系统中每个进程的核心数据结构,负责存储进程的所有信息。它是进程控制的唯一手段,也是最有效的手段。了解 task_struct 结构是理解 Linux 任务调度的关键。 task_struct 结构...
本文介绍了在 Linux 中获取 IPv4 和 IPv6 地址的方法,包括使用 `getifaddrs` 函数获取网络接口的信息,遍历链表,获取 IPv4 和 IPv6 地址,并使用 `inet_ntop` 函数将地址从二进制形式转换为字符串形式。