눈치 챘 겠지만이 작업을 수행하려면 약간의 추가 코드가 필요합니다.
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;
}
우리가'boost' 추가 패키지의 어떤 종류의 이와 같은 OS 고유의 기능을 제공 할 수 있다면 그것은 깔끔한 것. –