`
灵动的水
  • 浏览: 194567 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

在LINUX下获取网卡信息&&getifaddrs的时候遇到了内存方面的问题&&struct socketaddr和struct socketaddr_in的区

阅读更多
在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则不需要转换。
分享到:
评论

相关推荐

    task_struct在内核态堆栈的位置

    在Linux系统中,每个线程都有自己的内核态堆栈(kernel stack),这是操作系统为了处理中断和系统调用而为每个线程分配的一块内存区域。内核态堆栈中保存了线程执行系统调用或中断时的上下文信息,包括寄存器值、局部...

    linux-task_struct

    深入解析task_struct 结构体的几个字段

    pid_task_struct_pid_link.docx

    在Linux内核中,进程命名空间是实现容器和系统隔离的关键机制。进程命名空间允许不同的进程看到不同的进程ID视图,从而确保了进程间的独立性。`struct pid`和`struct task_struct`是内核中两个核心的数据结构,它们...

    解决Android下getifaddrs和freeifaddrs undefined reference 的问题

    `getifaddrs`和`freeifaddrs`是两个在Unix-like系统中广泛使用的C语言函数,用于获取这些信息。但在Android平台上,由于其基于Linux内核但并非完全兼容,可能会遇到这两个函数未定义的引用问题。本文将详细解析这个...

    app_struct_pythonstruct_freeood_

    在Python编程中,`struct`库是一个非常重要的模块,它提供了与C语言结构化数据类型进行转换的功能。在本项目"app_struct_pythonstruct_freeood_"中,主要关注的是如何使用`struct`库来处理IP地址的计算,特别是将一...

    structtype&def_struct

    在C和C++中,`struct`的使用方式略有不同,特别是在与`typedef`关键字结合使用时。 1. `struct`定义: 在C语言中,定义一个结构体类型通常需要使用`typedef`关键字来创建一个别名,使得后续的声明更简洁。例如: ``...

    ptr_struct_file.c与buff_type_test.c_ptr_struct_file_源代码_buff_type

    在给定的压缩包文件中,我们有两个C语言源代码文件——`ptr_struct_file.c`和`buff_type_test.c`。这些文件主要涉及到Linux环境下的程序开发,利用C语言进行编程。在这里,我们将深入探讨这两个文件可能涉及的关键...

    Qt获取IP地址、MAC地址等网卡信息,区分本地网卡、无线网卡和虚拟网卡

    获取网络接口信息可能需要管理员权限,因此在运行Qt应用程序时,如果遇到权限问题,可能需要以管理员身份启动。此外,对于虚拟网卡,如桥接或NAT网络,它们的标识可能更复杂,需要额外的逻辑来识别。 总结来说,...

    Linux系统如何构建sched_domain&sched_group hierarchy详解

    在 Linux 系统中,sched_domain 和 sched_group 层次结构的构建是通过对 CPU 的拓扑结构信息的获取和分析实现的。 首先,Linux 系统会从 cpuinfo_x86 结构中获取 CPU 的拓扑结构信息。cpuinfo_x86 结构包含了 CPU ...

    C++获得所有网卡信息

    在Linux环境下,可以使用`&lt;sys/socket.h&gt;`头文件中的`getifaddrs()`函数来获取网络接口的详细信息。这个函数会返回一个接口地址链表,每个元素包含了接口的名称、类型、地址等信息。通过遍历这个链表,我们可以获取...

    task_struct.

    在Linux操作系统中,`task_struct`是一个至关重要的数据结构,它代表了系统中的每一个进程。当我们谈论`task_struct`时,实际上是在讨论进程控制块(PCB,Process Control Block),这是理解和操纵进程行为的核心。 ...

    获取设备IP接口函数.zip_linux_seriouslqh_套接字_网络编程_获取Linux系统IP

    在Linux中,可以使用`getifaddrs`函数来获取网络接口的信息,包括IP地址。这个函数会返回一个链表,包含了所有网络接口的详细信息。每个接口都有一个`struct ifaddrs`结构体,其中包含了接口名称、地址家族(IPv4或...

    Android getifaddrs()和freeifaddrs()函数的实现

    在Android系统中,获取本地设备的网络接口信息是开发中常见的需求,这通常涉及到网络编程和底层系统调用。`getifaddrs()`和`freeifaddrs()`这两个函数是Unix-like系统中用于获取和释放网络接口地址信息的C语言接口。...

    python.struct_helper_0_01

    在Python中,与C语言结构体打交道通常涉及到对内存布局的理解,因为不同平台的字节顺序和大小可能会有所不同。 `struct`模块的核心在于它的`pack`和`unpack`函数。`pack`函数用于将Python值转化为字节串,而`unpack...

    C_C++中typedef_struct和struct的用法

    C_C++中typedef_struct和struct的用法 在 C/C++ 中,struct 和 typedef struct 是两个常用的数据类型定义方式,它们之间有着微妙的区别。本文将详细介绍 struct 和 typedef struct 的用法,并通过实例代码演示其...

    Linux内存描述符mm_struct实例详解

    Linux内存管理是操作系统的核心部分,尤其在服务器和嵌入式系统中,高效的内存管理对于系统的性能和稳定性至关重要。本文将深入解析Linux内核中的内存描述符`mm_struct`,它是管理进程虚拟地址空间的关键数据结构。 ...

    PIC-struct.rar_pic struct_pic的struct_单片机结构体

    在单片机编程中,尤其是使用C语言进行开发时,结构体(Struct)是一种非常重要的数据...在学习过程中,读者需要关注结构体的内存对齐、存储开销以及访问效率等方面的问题,这些都是使用结构体时需要考虑的关键因素。

    task_struct 数据结构1

    task_struct 数据结构是 Linux 操作系统中每个进程的核心数据结构,负责存储进程的所有信息。它是进程控制的唯一手段,也是最有效的手段。了解 task_struct 结构是理解 Linux 任务调度的关键。 task_struct 结构...

    linux下获取本机ip地址,ipv4和ipv6.pdf

    本文介绍了在 Linux 中获取 IPv4 和 IPv6 地址的方法,包括使用 `getifaddrs` 函数获取网络接口的信息,遍历链表,获取 IPv4 和 IPv6 地址,并使用 `inet_ntop` 函数将地址从二进制形式转换为字符串形式。

Global site tag (gtag.js) - Google Analytics