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

#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 

http://canlynet.iteye.com/blog/1440054

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 读取 或 设置 设备的 传输队列长度. 设置传输队列长度 是 特权操作.
SIOCSIFNAME
ifr_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)

 

 

 

 

posted @ 2013-04-17 14:32  静之深  阅读(7641)  评论(2编辑  收藏  举报