2012-11-06 38 views
5

Tôi đang viết ứng dụng khách/máy chủ đa hướng dựa trên thisthis; hoạt động tốtỔ cắm AF_NETLINK (netlink) sử dụng boost :: asio

Tuy nhiên, tôi cũng sẽ cần phải làm điều gì đó khi số lượng giao diện mạng đang hoạt động trong máy tính thay đổi, giống như chương trình trong phần ví dụ của this page.

Tôi đoán tôi nên sử dụng các công cụ trong boost :: ASIO :: địa phương, nhưng tôi không chắc liệu tôi nên sử dụng boost::asio::local::datagram_protocol hoặc boost::asio::local::stream_protocol hoặc ...

Một ví dụ về làm thế nào để làm điều gì đó như tương tự càng tốt sẽ thực sự hữu ích. Cảm ơn.

+0

Sẽ gọn gàng nếu chúng tôi có thể cung cấp các tính năng dành riêng cho hệ điều hành như thế này trong một số gói bổ sung 'boost'. –

Trả lời

11

Khi bạn nhận thấy có thêm một chút mã phải được viết để thực hiện việc này.

Netlink sử dụng Gia đình địa chỉ riêng (PF_NETLINK) và không phải là TCP hoặc UDP. Thay vào đó, nó sử dụng ổ cắm RAW. Vì nó là một gia đình riêng (không phải PF_INET hoặc PF_INET6), chúng ta cần tự định nghĩa nó.

Tôi đã sử dụng ổ cắm cục bộ unix cơ bản làm mẫu để triển khai (xem phần dưới cùng của chương trình thử nghiệm). Nếu bạn không muốn sao chép dán tất cả các mã, tôi cũng đặt nó trên 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); 
    } 
}; 

Giao thức:

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

Rồi từ đây tất cả chúng ta cần phải làm là tạo một ổ cắm thô và đọc nó:

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

cần sự giúp đỡ của bạn; http://stackoverflow.com/questions/23852866/netlink-giving-kernel-panic – SGG

Các vấn đề liên quan