recvmsg()在第一次通话时阻止,但在后续通话时不阻止

时间:2016-05-03 11:54:51

标签: c sockets linux-kernel client-server netlink

我的客户端 - 服务器C程序出现问题。

该计划有两个主要部分。在第一部分中,消息通过多播从内核模块发送到用户空间侦听器。我已多次尝试并测试了该程序的这一部分,并且按预期工作。

程序的第二部分将收到的消息传送到另一台机器(机器2)。因此,来自Machine 1的Userspace侦听器从内核获取消息,然后充当客户端,在机器1和机器2之间打开一个套接字。机器2中的服务器接收消息并将其打印到stdout。然后它等待另一条消息。

问题似乎是recvmsg()函数第一次阻塞但在后续迭代中没有阻塞。就好像套接字中的信息一直存在,因此阻止了recvmsg()阻塞。结果是同一条信息在循环中传输。

我在这个rec​​vmsg()问题上错了。也许有人有更多的经验,可以指出我正确的方向。代码和输出如下。非常感谢。

NetLinkUser_Client.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <unistd.h>
#include <errno.h>
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
#define MAX_PAYLOAD 1024
#define MY_GROUP    1
#define OUT_PORT "5001"
#define OUT_IP "192.168.xxx.xxx"

void client(char *msg) {
   int socketfd, portno, n;
   struct sockaddr_in serv_addr;
   struct hostent *server;

   portno = atoi(OUT_PORT);

   /* Create a socket point */
   socketfd = socket(AF_INET, SOCK_STREAM, 0);

   if (socketfd < 0) {
      perror("ERROR opening socket");
      exit(1);
   }

   server = gethostbyname(OUT_IP);

   if (server == NULL) {
      fprintf(stderr,"ERROR, no such host\n");
      exit(0);
   }

   bzero((char *) &serv_addr, sizeof(serv_addr));
   serv_addr.sin_family = AF_INET;
   bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);
   serv_addr.sin_port = htons(portno);

   /* Now connect to the server */
   if (connect(socketfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
      perror("ERROR connecting");
      exit(1);
   }

   /* Now send a message to the server, this message
          * will be read by server
        */
    char buffer[MAX_PAYLOAD];
    bzero(buffer,MAX_PAYLOAD);
    strcpy(buffer, msg);

    printf("\nThe contents of the buffer is: %s\n", buffer);

    printf("\nThe length of the buffer is: %d\n", strlen(buffer));

    /* Send message to the server */
    n = write(socketfd, buffer, strlen(buffer));

    if (n < 0) {
      perror("ERROR writing to socket");
      exit(1);
    }

    bzero(buffer,MAX_PAYLOAD);
    printf("%s\n",buffer);

    close(socketfd);
}
int main(void)
{
    int sock_fd;
    struct sockaddr_nl user_sockaddr;
    struct nlmsghdr *nl_msghdr;
    struct msghdr msghdr;
    struct iovec iov;

    char* kernel_msg;

    sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_USERSOCK);
    if(sock_fd<0)
    {
        printf("Error creating socket because: %s\n", strerror(errno));
        return -1;
    }


    memset(&user_sockaddr, 0, sizeof(user_sockaddr));
    user_sockaddr.nl_family = AF_NETLINK;
    user_sockaddr.nl_pid = getpid();
    user_sockaddr.nl_groups = MY_GROUP; 

    bind(sock_fd, (struct sockaddr*)&user_sockaddr, sizeof(user_sockaddr));
    while (1) {
        ssize_t recvmsg_err = 0;
        nl_msghdr = (struct nlmsghdr*) malloc(NLMSG_SPACE(1024));
        memset(nl_msghdr, 0, NLMSG_SPACE(1024));


        // The issue is not related to zeroing out msghdr
        printf("The struct member msghdr.msg_namelen has the value : %d before zeroing out\n", msghdr.msg_namelen);
        memset(&msghdr, 0, sizeof(msghdr));
        printf("The struct member msghdr.msg_namelen has the value : %d after zeroing out\n", msghdr.msg_namelen);

        memset(&iov, 0, sizeof(iov));

        iov.iov_base = (void*) nl_msghdr;
        iov.iov_len = NLMSG_SPACE(1024);

        msghdr.msg_name = (void*) &user_sockaddr;
        msghdr.msg_namelen = sizeof(user_sockaddr);
        msghdr.msg_iov = &iov;
        msghdr.msg_iovlen = 1;

        printf("The struct member msghdr.msg_namelen has the value : %d after initialization\n", msghdr.msg_namelen);
        printf("Waiting to receive message\n");

        // Execution not pausing here WHY??
        printf("recvmsg() should wait here\n");
        recvmsg_err = recvmsg(sock_fd, &msghdr, 0);

        if(recvmsg_err == -1)
        {
            perror("Error in recvmsg\n");
        }

        printf("The value returned by recvmsg() is %d\n", recvmsg_err);

        kernel_msg = (char*)NLMSG_DATA(nl_msghdr);
        printf("Kernel message: %s\n", kernel_msg); // print to android logs
        client(kernel_msg);

    }
    close(sock_fd);
}

MsgServer.c

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>

#include <netdb.h>
#include <netinet/in.h>

#include <string.h>
#define MAX_PAYLOAD 1024
void doprocessing (int sock) {
   int n;
   char buffer[MAX_PAYLOAD];
   bzero(buffer,MAX_PAYLOAD);
   n = read(sock,buffer,MAX_PAYLOAD);

   if (n < 0) {
      perror("ERROR reading from socket");
      exit(1);
   }
   printf("The length of the buffer is %d\n", strlen(buffer));
   printf("Here is the message: %s\n",buffer);

}
int main( int argc, char *argv[] ) {
   int sockfd, newsockfd, portno, clilen;
   char buffer[1024];
   struct sockaddr_in serv_addr, cli_addr;
   int n, pid;

   /* First call to socket() function */
   sockfd = socket(AF_INET, SOCK_STREAM, 0);

   if (sockfd < 0) {
      perror("ERROR opening socket");
      exit(1);
   }

   /* Initialize socket structure */
   bzero((char *) &serv_addr, sizeof(serv_addr));
   portno = 5001;

   serv_addr.sin_family = AF_INET;
   serv_addr.sin_addr.s_addr = INADDR_ANY;
   serv_addr.sin_port = htons(portno);

   /* Now bind the host address using bind() call.*/
   if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
      perror("ERROR on binding");
      exit(1);
   }

   /* Now start listening for the clients, here
      * process will go in sleep mode and will wait
      * for the incoming connection
   */

   listen(sockfd,5);
   clilen = sizeof(cli_addr);

   while (1) {
      printf("Waiting for initial connection in doProcessing() while loop\n");
      newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);

      if (newsockfd < 0) {
         perror("ERROR on accept");
         exit(1);
      }

      /* Create child process */
      pid = fork();

      if (pid < 0) {
         perror("ERROR on fork");
         exit(1);
      }

      if (pid == 0) {
         /* This is the client process */
         close(sockfd);
         doprocessing(newsockfd);
         exit(0);
      }
      else {
         close(newsockfd);
      }

   } /* end of while */
}

客户端示例输出

The struct member msghdr.msg_namelen has the value : 12 before zeroing out
The struct member msghdr.msg_namelen has the value : 0 after zeroing out
The struct member msghdr.msg_namelen has the value : 12 after initialization
Waiting to receive message
recvmsg() should wait here
The value returned by recvmsg() is 72
Kernel message: Progger:7,root,1537,1533,1261,4s,192.168.xxx.xxx,5001


The contents of the buffer is: Progger:7,root,1537,1533,1261,4s,192.168.xxx.xxx,5001


The length of the buffer is: 54

The struct member msghdr.msg_namelen has the value : 12 before zeroing out
The struct member msghdr.msg_namelen has the value : 0 after zeroing out
The struct member msghdr.msg_namelen has the value : 12 after initialization
Waiting to receive message
recvmsg() should wait here
The value returned by recvmsg() is 72
Kernel message: Progger:7,root,1537,1533,1261,4s,192.168.xxx.xxx,5001


The contents of the buffer is: Progger:7,root,1537,1533,1261,4s,192.168.xxx.xxx,5001


The length of the buffer is: 54

服务器示例输出

Waiting for initial connection in doProcessing() while loop
The length of the buffer is 54
Here is the message: Progger:7,root,1537,1533,1261,4s,192.168.xxx.xxx,5001

Waiting for initial connection in doProcessing() while loop
The length of the buffer is 54
Here is the message: Progger:7,root,1537,1533,1261,4s,192.168.xxx.xxx,5001

Waiting for initial connection in doProcessing() while loop
The length of the buffer is 54
Here is the message: Progger:7,root,1537,1533,1261,4s,192.168.xxx.xxx,5001

Waiting for initial connection in doProcessing() while loop
The length of the buffer is 54
Here is the message: Progger:7,root,1537,1533,1261,4s,192.168.xxx.xxx,5001

据我所知,考虑到Netlink,这可能难以重现。在此先感谢您的帮助,并为长篇文章感到抱歉。

编辑:我已更改代码以检查recvmsg()中的错误,如同建议但输出完全相同。

0 个答案:

没有答案