• 利用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;


  • 相关阅读:
    素因子分解
    【转载】一张表看懂LTE和5G NR的区别
    看国家宝藏,顺便学习一下国密算法
    LTE-Advanced(4G)主要技术学习:CA、CoMp、HetNet
    未来移动通信的需求与挑战
    傅里叶级数
    正余弦函数的复指数表示
    网络基础——相关面试考点
    操作系统——相关面试考点
    小米2015笔试编程题
  • 原文地址:https://www.cnblogs.com/yxwkf/p/5054183.html
Copyright © 2020-2023  润新知