2012-11-06 6 views
5

thisthis을 기반으로하는 멀티 캐스트 클라이언트/서버 응용 프로그램을 작성하고 있습니다. 위대한 작품.boost :: asio를 사용한 AF_NETLINK (netlink) 소켓

그러나 컴퓨터의 활성 네트워크 인터페이스 수가 변경되면 무언가를 수행해야합니다. 예를 들어 this page 섹션의 프로그램이 수행하는 것과 같습니다.

은 내가 부스트 : ASIO :: 지역에있는 도구를 사용해야합니다 같아요,하지만 난

가능한 한 비슷한 작업을 수행하는 방법의 예 ... 내가 boost::asio::local::datagram_protocol 또는 boost::asio::local::stream_protocol 이상을 사용할지 여부를 확실치 정말 도움이 될거야. 감사.

+0

우리가'boost' 추가 패키지의 어떤 종류의 이와 같은 OS 고유의 기능을 제공 할 수 있다면 그것은 깔끔한 것. –

답변

11

눈치 챘 겠지만이 작업을 수행하려면 약간의 추가 코드가 필요합니다.

Netlink는 자체 주소 패밀리 (PF_NETLINK)를 사용하며 TCP 또는 UDP가 아닙니다. 대신 RAW 소켓을 사용합니다. 개인용 패밀리 (PF_INET 또는 PF_INET6이 아님)이므로 자체 정의해야합니다.

기본 유닉스 로컬 소켓을 템플릿으로 사용하여이를 구현했습니다 (테스트 프로그램의 하단 참조). 당신은 모든 코드를 붙여 복사하지 않으려면, 나는 또한 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; 
}; 

을 그리고 우리가해야 할 모든 만들고 여기에서 원시 소켓과 그것을 읽어

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;  
} 
+0

에 도움이 필요합니다. http://stackoverflow.com/questions/23852866/netlink-giving-kernel-panic – SGG

관련 문제