您的位置:首页 > 理论基础 > 计算机网络

网络编程中一些小函数,getifaddrs()等

2013-04-17 14:32 197 查看
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>

#include <net/if.h>
#include <net/if_arp.h>
#include <arpa/inet.h>
#include <errno.h>

typedef long LONG;
typedef char CHAR;
#define CONST const

#ifndef  SUCCESS
#define  SUCCESS             0
#endif

#ifndef  FAIL
#define  FAIL               -1
#endif

LONG GetMac(CONST CHAR *pcIfName, CHAR *pcMac)
{
if (NULL == pcIfName || NULL == pcMac)
{
printf("NULL == pcIfName || NULL == pcMac\n");
return FAIL;
}

LONG lFd = 0, lRet = FAIL;
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, pcIfName);

lFd = socket(AF_INET, SOCK_STREAM, 0);
if(lFd < 0)
{
printf("socket fail\n");
return FAIL;
}

//lRet = ioctl(lFd, SIOCGIFHWADDR, &ifr, sizeof(ifr));
lRet = ioctl(lFd, SIOCGIFHWADDR, &ifr);
if(0 == lRet)
{
memcpy(pcMac, ifr.ifr_hwaddr.sa_data, 6);
printf("\nifr.ifr_hwaddr.sa_data is %s   \n",ifr.ifr_hwaddr.sa_data);
close(lFd);
return SUCCESS;
}
else
{
printf("ioctl fail\n");
close(lFd);
return FAIL;
}
}

LONG GetIp(CONST CHAR *pcIfName, CHAR *pcIp)
{
if (NULL == pcIfName || NULL == pcIp)
{
printf("NULL == pcIfName || NULL == pcIp\n");
return FAIL;
}

LONG lFd = 0, lRet = FAIL;
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, pcIfName);

lFd = socket(AF_INET, SOCK_STREAM, 0);
if(lFd < 0)
{
printf("socket fail\n");
return FAIL;
}

lRet = ioctl(lFd, SIOCGIFADDR, &ifr);
if(0 == lRet)
{
strncpy(pcIp,inet_ntoa(((struct sockaddr_in*)&(ifr.ifr_addr))->sin_addr),16);
close(lFd);
return SUCCESS;
}
else
{
printf("ioctl fail\n");
close(lFd);
return FAIL;
}
}

int main()
{
LONG lRet = FAIL;
CHAR szMac[6] = {0};
CHAR szIp[16] = {0};

CHAR szID[21] = {0};
int i=0;
int ulLen = 0;

lRet = GetMac("eth0", szMac);

for(i = 0; i < sizeof(szMac); i++)
{
//sprintf(szID + strlen((const char*)szID), "%02X", szMac[i]);
//ulLen = snprintf(szID, 1024, "%02X", szMac[i]);
//ulLen +=snprintf((szID + ulLen), 1024, "%02X", szMac[i]);
printf("%0x,",szMac[i]);
}
printf("\nlRet is %d,mac is %s\n",lRet,szID);

lRet = GetIp("eth0", szIp);

printf("lRet is %d,szIp is %s\n",lRet,szIp);

return 0;
}


getifaddrs()和struct ifaddrs的使用,获取本机IP

/article/3780637.html

ifaddrs结构体定义如下:

struct ifaddrs
{
struct ifaddrs  *ifa_next;    /* Next item in list */
char            *ifa_name;    /* Name of interface */
unsigned int     ifa_flags;   /* Flags from SIOCGIFFLAGS */
struct sockaddr *ifa_addr;    /* Address of interface */
struct sockaddr *ifa_netmask; /* Netmask of interface */
union
{
struct sockaddr *ifu_broadaddr; /* Broadcast address of interface */
struct sockaddr *ifu_dstaddr; /* Point-to-point destination address */
} ifa_ifu;
#define              ifa_broadaddr ifa_ifu.ifu_broadaddr
#define              ifa_dstaddr   ifa_ifu.ifu_dstaddr
void            *ifa_data;    /* Address-specific data */
};


ifa_next指向链表的下一个成员;ifa_name是接口名称,以0结 尾的字符串,比如eth0,lo;ifa_flags是接口的标识位(比如当IFF_BROADCAST或IFF_POINTOPOINT设置到此标识位 时,影响联合体变量ifu_broadaddr存储广播地址或ifu_dstaddr记录点对点地址);ifa_netmask存储该接口的子网掩码;结 构体变量存储广播地址或点对点地址(见括弧介绍ifa_flags);ifa_data存储了该接口协议族的特殊信息,它通常是NULL(一般不关注 他)。

函数getifaddrs(int getifaddrs (struct ifaddrs **__ifap))获取本地网络接口信息,将之存储于链表中,链表头结点指针存储于__ifap中带回,函数执行成功返回0,失败返回-1,且为errno赋值。
很显然,函数getifaddrs用于获取本机接口信息,比如最典型的获取本机IP地址。

/* Standard interface flags. */
enum
{
IFF_UP = 0x1, /* Interface is up. */
# define IFF_UP IFF_UP
IFF_BROADCAST = 0x2, /* Broadcast address valid. */
# define IFF_BROADCAST IFF_BROADCAST
IFF_DEBUG = 0x4, /* Turn on debugging. */
# define IFF_DEBUG IFF_DEBUG
IFF_LOOPBACK = 0x8, /* Is a loopback net. */
# define IFF_LOOPBACK IFF_LOOPBACK
IFF_POINTOPOINT = 0x10, /* Interface is point-to-point link. */
# define IFF_POINTOPOINT IFF_POINTOPOINT
IFF_NOTRAILERS = 0x20, /* Avoid use of trailers. */
# define IFF_NOTRAILERS IFF_NOTRAILERS
IFF_RUNNING = 0x40, /* Resources allocated. */
# define IFF_RUNNING IFF_RUNNING
IFF_NOARP = 0x80, /* No address resolution protocol. */
# define IFF_NOARP IFF_NOARP
IFF_PROMISC = 0x100, /* Receive all packets. */
# define IFF_PROMISC IFF_PROMISC

/* Not supported */
IFF_ALLMULTI = 0x200, /* Receive all multicast packets. */
# define IFF_ALLMULTI IFF_ALLMULTI

IFF_MASTER = 0x400, /* Master of a load balancer. */
# define IFF_MASTER IFF_MASTER
IFF_SLAVE = 0x800, /* Slave of a load balancer. */
# define IFF_SLAVE IFF_SLAVE

IFF_MULTICAST = 0x1000, /* Supports multicast. */
# define IFF_MULTICAST IFF_MULTICAST

IFF_PORTSEL = 0x2000, /* Can set media type. */
# define IFF_PORTSEL IFF_PORTSEL
IFF_AUTOMEDIA = 0x4000, /* Auto media select active. */
# define IFF_AUTOMEDIA IFF_AUTOMEDIA
IFF_DYNAMIC = 0x8000 /* Dialup device with changing addresses. */
# define IFF_DYNAMIC IFF_DYNAMIC
};

网络设备 的 套接字(socket) 接口

http://blog.sina.com.cn/s/blog_4bb620d50100083u.html

#include <sys/ioctl.h>

#include <net/if.h>

描述 (DESCRIPTION)

本手册 描述 用于 配置 网络设备 的 套接字(socket) 接口.

Linux 支持 一些 配置 网络设备 的 标准 ioctl.
他们用于任意的套接字 描述符, 而 无须 了解 其 类型 或 系列. 他们
传递一个 ifreq 结构:

struct ifreq

{

char            ifr_name[IFNAMSIZ];   /* Interface name */
union {
struct sockaddr       ifr_addr;
struct sockaddr       ifr_dstaddr;
struct sockaddr       ifr_broadaddr;
struct sockaddr       ifr_netmask;
struct sockaddr       ifr_hwaddr;
short                 ifr_flags;
int                   ifr_ifindex;
int                   ifr_metric;
int                   ifr_mtu;
struct ifmap          ifr_map;
char                  ifr_slave[IFNAMSIZ];
char                  ifr_newname[IFNAMSIZ];
char *                ifr_data;
};
}

struct ifconf
{
int ifc_len;       /* size of buffer */

union {

char *    ifc_buf; /* buffer ddress */
struct ifreq *ifc_req; /* array of structures */

};
};

一般说来, ioctl 通过 把 ifr_name 设置为 接口 的 名字 来指定 将要 操作 的 设备. 结构的 其他成员 可以 分享 内存.


IOCTLS

如果 某个 ioctl 标记为 特权操作, 那么 操作时 需要 有效uid 为 0, 或者 拥有 CAP_NET_ADMIN 能力. 否则 将 返回 EPERM .

SIOCGIFNAME

给定 ifr_ifindex, 返回 ifr_name 中 的 接口名字. 这是唯一 返回 ifr_name 内容 的 ioctl.

SIOCGIFINDEX把 接口 的 索引 存入 ifr_ifindex.SIOCGIFFLAGS, SIOCSIFFLAGS读取 或 设置 设备的 活动标志字. ifr_flags 包含下列值的屏蔽位:
设备标志
IFF_UP接口正在运行.
IFF_BROADCAST有效的广播地址集.
IFF_DEBUG内部调试标志.
IFF_LOOPBACK这是自环接口.
IFF_POINTOPOINT这是点到点的链路接口.
IFF_RUNNING资源已分配.
IFF_NOARP无arp协议, 没有设置第二层目的地址.
IFF_PROMISC接口为杂凑(promiscuous)模式.
IFF_NOTRAILERS避免使用trailer .
IFF_ALLMULTI接收所有组播(multicast)报文.
IFF_MASTER主负载平衡群(bundle).
IFF_SLAVE从负载平衡群(bundle).
IFF_MULTICAST支持组播(multicast).
IFF_PORTSEL可以通过ifmap选择介质(media)类型.
IFF_AUTOMEDIA自动选择介质.
IFF_DYNAMIC接口关闭时丢弃地址.
设置 活动标志字 是 特权操作, 但是 任何进程 都可以读取标志字.

SIOCGIFMETRIC, SIOCSIFMETRIC使用 ifr_metric 读取 或 设置 设备的 metric 值.
该功能目前 还没有 实现. 读取操作 使 ifr_metric 置 0,
而设置操作则 返回 EOPNOTSUPP.SIOCGIFMTU, SIOCSIFMTU使用 ifr_mtu 读取 或 设置 设备的 MTU(最大传输单元). 设置
MTU 是 特权操作. 过小的 MTU 可能 导致 内核 崩溃.SIOCGIFHWADDR, SIOCSIFHWADDR使用 ifr_hwaddr 读取 或 设置 设备的 硬件地址.
设置硬件地址 是 特权操作.SIOCSIFHWBROADCAST使用 ifr_hwaddr 读取 或 设置 设备的 硬件广播地址.
这是个特权操作.SIOCGIFMAP, SIOCSIFMAP使用 ifr_map 读取 或 设置 接口的 硬件参数.
设置这个参数是 特权操作.
struct ifmap

{

unsigned long   mem_start;

unsigned long   mem_end;

unsigned short  base_addr;

unsigned char   irq;

unsigned char   dma;

unsigned char   port;

};


对 ifmap 结构 的 解释 取决于 设备驱动程序 和 体系结构.

SIOCADDMULTI, SIOCDELMULTI使用 ifr_hwaddr 在 设备的 链路层 组播过滤器 (multicase filter) 中 添加 或 删除 地址. 这些是 特权操作. 参看 packet(7).SIOCGIFTXQLEN, SIOCSIFTXQLEN使用 ifr_qlen 读取 或 设置 设备的 传输队列长度. 设置传输队列长度 是 特权操作.SIOCSIFNAMEifr_ifindex 中 指定的 接口名字 改成 ifr_newname. 这是个 特权操作.SIOCGIFCONF返回 接口地址(传输层) 列表. 出于 兼容性, 目前 只代表 AF_INET 地址. 用户 传送 一个 ifconf 结构 作为 ioctl 的 参数. 其中 ifc_req 包含 一个 指针 指向 ifreq 结构数组, 他的长度以字节 为单位 存放在 ifc_len 中. 内核 用 所有 当前的 L3(第三层?) 接口地址 填充 ifreqs, 这些 接口 正在 运行: ifr_name 存放 接口名字 (eth0:1等), ifr_addr 存放地址. 内核 在 ifc_len 中 返回 实际长度; 如果 他 等于初始长度, 表示溢出了, 用户 应该 换一个 大些的 缓冲区 重试 一下. 没有 发生错误时 ioctl 返回 0, 否则 返回 -1, 溢出 不算 错误.
大多数 协议 使用 自己的 ioctl 配置 协议 特定的 接口 操作. 具体情况参看 协议的 帮助手册. 要配置 IP 地址 可以 参看 ip(7).

另外, 某些 设备 有 专用的 ioctl, 这里 不做 叙述.

注意 (NOTE)

严格说来 SIOCGIFCONF 是 专门 针对 IP 的, 它 属于 ip(7).

注意 (NOTE)

可以 通过 /proc/net/dev 看到 没有 地址 或 没有 IFF_RUNNING 标志 的 接口名字.

/* Interface request structure used for socket ioctl's. All interface
ioctl's must have parameter definitions which begin with ifr_name.
The remainder may be interface specific. */

struct ifreq
{
# define IFHWADDRLEN 6
# define IFNAMSIZ IF_NAMESIZE
union
{
char ifrn_name[IFNAMSIZ]; /* Interface name, e.g. "en0". */
} ifr_ifrn;

union
{
struct sockaddr ifru_addr;
struct sockaddr ifru_dstaddr;
struct sockaddr ifru_broadaddr;
struct sockaddr ifru_netmask;
struct sockaddr ifru_hwaddr;
short int ifru_flags;
int ifru_ivalue;
int ifru_mtu;
struct ifmap ifru_map;
char ifru_slave[IFNAMSIZ]; /* Just fits the size */
char ifru_newname[IFNAMSIZ];
__caddr_t ifru_data;
} ifet_ifru;
};
# define ifr_name ifr_ifrn.ifrn_name /* interface name */
# define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */
# define ifr_addr ifr_ifru.ifru_addr /* address */
# define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-p lnk */
# define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */
# define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */
# define ifr_flags ifr_ifru.ifru_flags /* flags */
# define ifr_metric ifr_ifru.ifru_ivalue /* metric */
# define ifr_mtu ifr_ifru.ifru_mtu /* mtu */
# define ifr_map ifr_ifru.ifru_map /* device map */
# define ifr_slave ifr_ifru.ifru_slave /* slave device */
# define ifr_data ifr_ifru.ifru_data /* for use by interface */
# define ifr_ifindex ifr_ifru.ifru_ivalue /* interface index */
# define ifr_bandwidth ifr_ifru.ifru_ivalue /* link bandwidth */
# define ifr_qlen ifr_ifru.ifru_ivalue /* queue length */
# define ifr_newname ifr_ifru.ifru_newname /* New name */
# define _IOT_ifreq _IOT(_IOTS(char),IFNAMSIZ,_IOTS(char),16,0,0)
# define _IOT_ifreq_short _IOT(_IOTS(char),IFNAMSIZ,_IOTS(short),1,0,0)
# define _IOT_ifreq_int _IOT(_IOTS(char),IFNAMSIZ,_IOTS(int),1,0,0)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: