如何使用netlink进行IPC?

How to use netlink for IPC?

我的项目需要使用 Netlink 进行 IPC,参考文献是 Netlink unicast. I had done some changes in code. Firstly, I started both receiver and sender, then I inputted the sender's pid to receiver and later inputted receiver's pid to sender. But the receiver didn't receive the message. I also refer Is anyone using netlink for IPC?,其中 none 个正在运行。我的代码有什么问题吗?

收件人代码:

#include <sys/socket.h>
#include <linux/netlink.h>
#include <stdio.h>
#include <malloc.h>
#include <stdio.h>
#include <string.h>

#define NLINK_MSG_LEN 1024
#define NETLINK_USER 31

int main() {
  int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
  //int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_USERSOCK);
  //int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_USER);
  printf("Inside recv main\n");

  if (fd < 0) {
    printf("Socket creation failed. try again\n");
    return -1;
  }

  /* Declare for src NL sockaddr, dest NL sockaddr, nlmsghdr, iov, msghr */
  struct sockaddr_nl src_addr, dest_addr;
  memset(&src_addr, 0, sizeof(src_addr));
  memset(&dest_addr, 0, sizeof(dest_addr));

  //allocate buffer for netlink message which is message header + message payload
  struct nlmsghdr *nlh =(struct nlmsghdr *) malloc(NLMSG_SPACE(NLINK_MSG_LEN));
  memset(nlh, 0, NLMSG_SPACE(NLINK_MSG_LEN));

  //fill the iovec structure
  struct iovec iov;
  memset(&iov, 0, sizeof(iov));
  //define the message header for message
  //sending
  struct msghdr msg;
  memset(&msg, 0, sizeof(msg));

  int sender_pid;
  printf("Receiver process id: %d\n", getpid());
  printf("Sender process id: ");
  scanf("%d", &sender_pid);

  src_addr.nl_family = AF_NETLINK;   //AF_NETLINK socket protocol
  src_addr.nl_pid = getpid();               //application unique id
  src_addr.nl_groups = 0;            //specify not a multicast communication

  dest_addr.nl_family = AF_NETLINK; // protocol family
  dest_addr.nl_pid = sender_pid;   //destination process id
  dest_addr.nl_groups = 0; 

  nlh->nlmsg_len = NLMSG_SPACE(NLINK_MSG_LEN);   //netlink message length 
  nlh->nlmsg_pid = getpid();                            //src application unique id
  nlh->nlmsg_flags = 0;

  iov.iov_base = (void *)nlh;     //netlink message header base address
  iov.iov_len = nlh->nlmsg_len;   //netlink message length
  msg.msg_name = (void *)&dest_addr;
  msg.msg_namelen = sizeof(dest_addr);
  msg.msg_iov = &iov;
  msg.msg_iovlen = 1;

  //attach socket to unique id or address
  if(bind(fd, (struct sockaddr *)&src_addr, sizeof(src_addr)) < 0) {
    printf("Bind failed");
    return -1;
  }

  /* Listen forever in a while loop */
  while (1) {
    //receive the message
    recvmsg(fd, &msg, 0);
    printf("Received message: %s\n", (char *)NLMSG_DATA(nlh));
  }
  close(fd); // close the socket
}

发件人代码:

#include <sys/socket.h>
#include <linux/netlink.h>
#include <stdio.h>
#include <malloc.h>
#include <stdio.h>
#include <string.h>

#define NLINK_MSG_LEN 1024
#define NETLINK_USER 31

int main() {
  int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
  //int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_USERSOCK);
  //int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_USER);
  printf("Inside send main\n");

  if (fd < 0) {
    printf("Socket creation failed. try again\n");
    return -1;
  }

  /* Declare for src NL sockaddr, dest NL sockaddr, nlmsghdr, iov, msghr */
  struct sockaddr_nl src_addr, dest_addr;
  memset(&src_addr, 0, sizeof(src_addr));
  memset(&dest_addr, 0, sizeof(dest_addr));

  //allocate buffer for netlink message which is message header + message payload
  struct nlmsghdr *nlh =(struct nlmsghdr *) malloc(NLMSG_SPACE(NLINK_MSG_LEN));
  memset(nlh, 0, NLMSG_SPACE(NLINK_MSG_LEN));

  //fill the iovec structure
  struct iovec iov;
  memset(&iov, 0, sizeof(iov));
  //define the message header for message
  //sending
  struct msghdr msg;
  memset(&msg, 0, sizeof(msg));

  int receiver_pid;
  printf("Sender process id: %d\n", getpid());
  printf("Receiver process id: ");
  scanf("%d", &receiver_pid);

  src_addr.nl_family = AF_NETLINK;   //AF_NETLINK socket protocol
  src_addr.nl_pid = getpid();               //application unique id
  src_addr.nl_groups = 0;            //specify not a multicast communication

  dest_addr.nl_family = AF_NETLINK; // protocol family
  dest_addr.nl_pid = receiver_pid;   //destination process id
  dest_addr.nl_groups = 0; 

  nlh->nlmsg_len = NLMSG_SPACE(NLINK_MSG_LEN);   //netlink message length 
  nlh->nlmsg_pid = getpid();                            //src application unique id
  nlh->nlmsg_flags = 0;
  strcpy(NLMSG_DATA(nlh), "Hello World !");   //copy the payload to be sent

  iov.iov_base = (void *)nlh;     //netlink message header base address
  iov.iov_len = nlh->nlmsg_len;   //netlink message length
  msg.msg_name = (void *)&dest_addr;
  msg.msg_namelen = sizeof(dest_addr);
  msg.msg_iov = &iov;
  msg.msg_iovlen = 1;

  //attach socket to unique id or address
  if(bind(fd, (struct sockaddr *)&src_addr, sizeof(src_addr)) < 0) {
    printf("Bind failed");
    return -1;
  }

  //send the message
  sendmsg(fd, &msg, 0);
  printf("Send message %s\n", (char *)NLMSG_DATA(nlh));

  close(fd); // close the socket
}

您对 socket 使用了错误的协议类型。唯一可以做你想做的,用户-space 进程之间的 IPC,是 NETLINK_USERSOCK.

请记住,在安排与 PID 的通信时,您可能会错过一些消息...为了验证通信是否发生,您可以留下 msg_name NULL 对于接收者,这不会产生不良影响 - 这样做并更改协议,您的代码将按预期工作。