首页 > 代码库 > 利用sendmsg和recvmsg来指定发送接口或者获取接收数据接口

利用sendmsg和recvmsg来指定发送接口或者获取接收数据接口

前言

    sendmsg和recvmsg函数是一对相对下层的套接字发送、接受函数。通过这对函数,我们可以设置或者取得数据包的一些额外的控制信息,这些信息中比较常用的就是本文要介绍的发送、接受接口信息。通过这对函数,我们可以指定一个数据包发送的时候使用的接口(网卡)或者获得一个接受到数据包的来源接口。

sendmsg函数使用

sendmsg(fd, &mhdr, 0)函数中最重要的就是msghdr结构体。其定义如下:
struct msghdr {
    void         *msg_name; #发送地址
    socklen_t    msg_namelen; #前者长度
    struct iovec *msg_iov;#发送数据缓冲区的指针
    size_t       msg_iovlen;#发送数据长度
    void         *msg_control; #控制数据指针
    size_t       msg_controllen;#控制数据长度
    int          msg_flags;
};

    在我们发送一个数据包之前,要首先把要发送的数据以及相关控制信息填写到这个结构体中。
    这个结构体中包含的是数据以及控制信息的指针,因此在发送之前我们还需要另外为数据和控制信息分配空间。
    数据就不用说了,直接char buf[MAX_MSG_SIZE]即可。难点在于控制信息。
    首先要定义一个msghdr 结构体,这个结构体用来存储所有的控制信息和发送的数据包:
struct msghdr mhdr;
    接着定义控制信息结构体cmsghdr 
struct cmsghdr *cmsg;
    我们要首先通过CMSG_SPACE 宏计算出控制信息cmsghdr结构体所需的空间大小,接着为控制信息结构体指针分配内存。cmsghdr的大小跟你要填写的控制消息有关。我们这里要填写的是发送接口控制信息,这个控制信息还需要一个结构体struct in6_pktinfo结构体来承载,所以这里cmsghdr的大小则跟in6_pktinfo的大小有关:

struct in6_pktinfo pk;//定义接口控制数据结构
pk.ini_index=1;//指定接口(这里的1是接口索引号)
cmsglen =  CMSG_SPACE (sizeof(pk));//计算cmsghdr结构在mhdr中所需的大小
mhdr.msg_control=(void *)malloc(cmsglen);//为cmsghdr分配内存,并在mhdr中填写控制信息的指针
mhdr.msg_controllen=cmsglen;
cmsg =  CMSG_FIRSTHDR (&mhdr);//我们利用CMSG_FIRSTHDR找到控制信息在mhdr结构体中的真正地址
//利用CMSG_LEN算出控制信息cmsghdr结构中真正的控制数据的长度
cmsg->cmsg_len = CMSG_LEN(sizeof(*pk));
cmsg->cmsg_level = IPPROTO_IPV6;//填写cmsghdr控制信息结构体
cmsg->cmsg_type = IPV6_PKTINFO;
//CMSG_DATA(cmsg) 可以找到真正的控制信息在cmsghdr结构体中的位置,之后我们就可以利用memcpy把控制结构体的数据拷贝到cmsg中:
memcpy(CMSG_DATA(cmsg), pk, sizeof(*pk));
以上是发送的过程,接收过程跟发送过程类似。
最好需要注意的是,要发送以及接收这些控制信息,我们必须要设置套接字选项:
int val = 1;
if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
                       &val, sizeof(val)) < 0)
                return -1;
        if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVDSTOPTS,
                       &val, sizeof(val)) < 0)
                return -1;
        if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVRTHDR,
                       &val, sizeof(val)) < 0)
                return -1;