AF_NETLINK(网络链路)插座使用boost :: ASIO [英] AF_NETLINK (netlink) sockets using boost::asio

查看:321
本文介绍了AF_NETLINK(网络链路)插座使用boost :: ASIO的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的基础上的这个并的;这工作的伟大。

I'm writing multicast client/server application based on this and this; which work great.

不过,我还需要做些什么时候活动的网络接口在电脑中更改的数量,像什么的此页面呢。

However, I would also need to do something when the number of active network interfaces in the computer changes, something like what the program in the example section of this page does.

我想我应该在的boost :: ASIO ::本地使用的工具,但我不确定我是否应该使用的boost ::支持ASIO ::当地:: datagram_protocol 的boost ::支持ASIO ::当地:: stream_protocol 或...

I guess I should use the tools in boost::asio::local, but I am unsure whether I should use boost::asio::local::datagram_protocol or boost::asio::local::stream_protocol or...

如何做到尽可能相似的东西的一个例子是真的很有帮助。谢谢你。

An example of how to do something as similar as possible would be really helpful. Thanks.

推荐答案

当你注意到有一点点额外的code有得到书面做到这一点。

As you noticed there's a little bit extra code that has to get written to do this.

网络链路使用它自己的地址族(PF_NETLINK),而不是TCP或UDP。相反,它使用RAW插槽。既然是私人家庭(不PF_INET或PF_INET6),我们需要定义它自己。

Netlink uses its own Address Family (PF_NETLINK) and isn't TCP or UDP. Instead it uses RAW sockets. Since it is a private family (not PF_INET or PF_INET6) we need to define it ourselves.

我用了一个基本的UNIX本地套接字作为模板来实现这个(见测试程序的底部)。如果你不想要复制粘贴所有code,我也把它在github( http://github.com/gille / boost_netlink ):

I used a basic unix local socket as a template to implement this (see the bottom for test program). If you don't want to copy paste all the code, I also put it on github (http://github.com/gille/boost_netlink):

template <typename Protocol>
class nl_endpoint
{
private:
    sockaddr_nl sockaddr;
public:
    /// The protocol type associated with the endpoint.
    typedef Protocol protocol_type;
    typedef boost::asio::detail::socket_addr_type data_type;        

    /// Default constructor.
    nl_endpoint()
    {
        sockaddr.nl_family = PF_NETLINK;
        sockaddr.nl_groups = 0;
        sockaddr.nl_pid = getpid(); 
    }

    /// Construct an endpoint using the specified path name.
    nl_endpoint(int group, int pid=getpid())
    {
        sockaddr.nl_family = PF_NETLINK;
        sockaddr.nl_groups = group;
        sockaddr.nl_pid = pid;
    }

    /// Copy constructor.
    nl_endpoint(const nl_endpoint& other)
    {
        sockaddr = other.sockaddr;
    }

    /// Assign from another endpoint.
    nl_endpoint& operator=(const nl_endpoint& other)
    {
        sockaddr = other.sockaddr;
        return *this;
    }

    /// The protocol associated with the endpoint.
    protocol_type protocol() const
    {
        return protocol_type();
    }

    /// Get the underlying endpoint in the native type.
    data_type* data()
    {
        return &sockaddr;
    }

    /// Get the underlying endpoint in the native type.
    const data_type* data() const
    {
        return (struct sockaddr*)&sockaddr;
    }

    /// Get the underlying size of the endpoint in the native type.
    std::size_t size() const
    {
        return sizeof(sockaddr);
    }

    /// Set the underlying size of the endpoint in the native type.
    void resize(std::size_t size)
    {
    /* nothing we can do here */
    }

    /// Get the capacity of the endpoint in the native type.
    std::size_t capacity() const
    {
        return sizeof(sockaddr);
    }

    /// Compare two endpoints for equality.
    friend bool operator==(const nl_endpoint<Protocol>& e1,
               const nl_endpoint<Protocol>& e2)
    {
        return e1.sockaddr == e2.sockaddr;
    }

    /// Compare two endpoints for inequality.
    friend bool operator!=(const nl_endpoint<Protocol>& e1,
               const nl_endpoint<Protocol>& e2)
    {
        return !(e1.sockaddr == e2.sockaddr);
    }

    /// Compare endpoints for ordering.
    friend bool operator<(const nl_endpoint<Protocol>& e1,
              const nl_endpoint<Protocol>& e2)
    {
        return e1.sockaddr < e2.sockaddr;
    }

    /// Compare endpoints for ordering.
    friend bool operator>(const nl_endpoint<Protocol>& e1,
              const nl_endpoint<Protocol>& e2)
    {
        return e2.sockaddr < e1.sockaddr;
    }

    /// Compare endpoints for ordering.
    friend bool operator<=(const nl_endpoint<Protocol>& e1,
               const nl_endpoint<Protocol>& e2)
    {
        return !(e2 < e1);
    }

    /// Compare endpoints for ordering.
    friend bool operator>=(const nl_endpoint<Protocol>& e1,
               const nl_endpoint<Protocol>& e2)
    {
        return !(e1 < e2);
    }
};

的协议:

class nl_protocol
{
private:
    int proto; 
public:
    nl_protocol() {
        proto = 0;
    }
    nl_protocol(int proto) {
        this->proto = proto;
    }
    /// Obtain an identifier for the type of the protocol.
    int type() const
    {
        return SOCK_RAW;
    }
    /// Obtain an identifier for the protocol.
    int protocol() const
    {
        return proto;
    }
    /// Obtain an identifier for the protocol family.
    int family() const
    {
        return PF_NETLINK;
    }

    typedef nl_endpoint<nl_protocol> endpoint;
    typedef boost::asio::basic_raw_socket<nl_protocol> socket;
};

然后从这里我们需要做的是创建一个原始套接字,并阅读:

Then from here all we need to do is create a raw socket and read it:

void handle_netlink(struct nlmsghdr *nlm);

int main(int argc, char* argv[])
{
    try
    {
        boost::asio::io_service io_service;
        boost::asio::basic_raw_socket<nl_protocol> s(io_service ); 

        s.open(nl_protocol(NETLINK_ROUTE));
        s.bind(nl_endpoint<nl_protocol>(RTMGRP_LINK)); 

        char buffer[max_length];
        int bytes;

        while((bytes=s.receive(boost::asio::buffer(buffer, max_length)))) {
             struct nlmsghdr *nlm;

            for (nlm = (struct nlmsghdr *)buffer;
              NLMSG_OK(nlm, (size_t)bytes);
              nlm = NLMSG_NEXT(nlm, bytes))
            {
            handle_netlink(nlm);
            }
        }
    }
    catch (std::exception& e)
    {
        std::cerr << "Exception: " << e.what() << "\n";
    }        
    return 0;
}

/* This code just prints out what interface went up or down */    
void handle_netlink(struct nlmsghdr *nlm) {
    int len;
    char ifname[IF_NAMESIZE + 1];
    ifinfomsg *ifi;
    rtattr *rta;

    if (nlm->nlmsg_type == RTM_NEWLINK) {
        len = nlm->nlmsg_len - sizeof(*nlm);
        if ((size_t)len < sizeof(*ifi)) {
            errno = EBADMSG;
            return;
        }
        ifi = (ifinfomsg*)NLMSG_DATA(nlm);
        if (ifi->ifi_flags & IFF_LOOPBACK)
            return;

        rta = (rtattr *) ((char *)ifi + NLMSG_ALIGN(sizeof(*ifi)));
        len = NLMSG_PAYLOAD(nlm, sizeof(*ifi));
        ifname[0] = '\0';
        while (RTA_OK(rta, len)) {
            switch (rta->rta_type) {
                case IFLA_IFNAME:
                strncpy(ifname, (char*)RTA_DATA(rta), sizeof(ifname));
                break;
                default:
                    break;
            }
            rta = RTA_NEXT(rta, len);       
        }
    }
    if (nlm->nlmsg_type == RTM_NEWLINK)
        len = ifi->ifi_change == ~0U ? 1 : 0;

    std::cout << "Interface " << ifname << " changed status, now: ";
    if((ifi->ifi_flags&IFF_LOWER_UP)==IFF_LOWER_UP)
        std::cout << " Up" << std::endl;
    else
        std::cout << " Down" << std::endl;    
}

这篇关于AF_NETLINK(网络链路)插座使用boost :: ASIO的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆