Linux套接字编程调试?

Linux套接字编程调试?,linux,linux-kernel,sockets,linux-device-driver,Linux,Linux Kernel,Sockets,Linux Device Driver,我有这样一个函数: static int rcv_kern(int sock, void *buf, int len, struct sockaddr *addr, socklen_t *addrlen) { struct timeval timeout = {1, 0}; fd_set set; int status; FD_SET(sock, &set); if ((status = select(sock + 1, &se

我有这样一个函数:

static int
rcv_kern(int sock, void *buf, int len, struct sockaddr *addr,
     socklen_t *addrlen)
{
    struct timeval timeout = {1, 0};
    fd_set set;
    int status;

    FD_SET(sock, &set);
    if ((status = select(sock + 1, &set, NULL, NULL, &timeout)) == 0) {
        FD_ZERO(&set);
        fprintf(stderr, 
            "timeout while receiving answer from kernel\n");
        exit(1);
    } else if (status == -1) {
        FD_ZERO(&set);
        perror("recvfrom failed");
        exit(1);
    }
    FD_ZERO(&set);
    return recvfrom(sock, buf, len, 0, addr, addrlen);
}
static int
rcv_kern(int sock, void *buf, int len, struct sockaddr *addr,
     socklen_t *addrlen)
{
    struct timeval timeout = {1, 0};
    fd_set set;
    int status;

    FD_ZERO(&set);
    FD_SET(sock, &set);
    if ((status = select(sock + 1, &set, NULL, NULL, &timeout)) == 0) {
        fprintf(stderr, 
                "timeout while receiving answer from kernel\n");
        exit(1);
    } else if (status < 0) {
        perror("recvfrom failed");
        exit(1);
    }
    if ((status = recvfrom(sock, buf, len, 0, addr, addrlen)) < 0) {
        perror("recvfrom error");
        exit(1);
    }
    if (status == 0) {
        fprintf(stderr, "kernel closed socket\n");
        exit(1);
    }
    return status;
}

用于使用netlink从内核空间接收消息。但是当我运行它时,结果总是从源代码中显示消息“从内核接收应答时超时”,这是因为“select”方法总是返回“0”。我不知道原因,谁能给我一些建议,谢谢。

与超时无关,但您需要在FD_set(sock,&set)之前设置FD_ZERO(&set),否则FD_set将未初始化,可能包含许多设置位。此外,退出之前的FD_ZERO()也是毫无意义的。

与超时无关,但您需要在FD_set(sock,&set)之前设置FD_ZERO(&set),否则FD_set将未初始化,并且可能包含许多设置位。另外,退出之前的FD_ZERO()也是毫无意义的。

我在内核空间研究了我的代码,我知道内核无法使用“skb_dequeue(&sk->sk_receive_queue)”方法从客户端接收消息。
我不知道它是如何发生的。

我在内核空间研究了我的代码,我知道内核无法使用“skb_dequeue(&sk->sk_receive_queue)”方法从客户端接收消息。
我不知道它是怎么发生的。

对于初学者,当超时发生时,您可以通过打印
strerror(errno)
(打印errno也是明智的)来找出实际错误

至于在没有errno的情况下猜测问题可能是什么,请注意,不能保证有任何内容可以阅读;即使您通过accept(2)获得了套接字,也可能只是建立了一个连接,但客户机没有抽出时间向其写入。通常情况下,您不会只进行一次选择(2);您希望有一个主循环,它会一直调用select(2),直到程序想要退出为止,因为超时可能在任何时候出于任何原因发生

其他可能的问题:

  • 客户端无法连接
  • 您未能正确绑定套接字
  • 在调用bind(2)之后,您忘记调用服务器套接字上的listen(2)

如果您使用的是IP套接字,您可以使用Wireshark查看您的网络流量,以查看客户端是否正在执行您预期的操作。

对于初学者,您可以通过在超时发生时打印出
strerror(errno)
(打印errno也是明智的)来找出实际错误

至于在没有errno的情况下猜测问题可能是什么,请注意,不能保证有任何内容可以阅读;即使您通过accept(2)获得了套接字,也可能只是建立了一个连接,但客户机没有抽出时间向其写入。通常情况下,您不会只进行一次选择(2);您希望有一个主循环,它会一直调用select(2),直到程序想要退出为止,因为超时可能在任何时候出于任何原因发生

其他可能的问题:

  • 客户端无法连接
  • 您未能正确绑定套接字
  • 在调用bind(2)之后,您忘记调用服务器套接字上的listen(2)
如果您使用的是IP套接字,您可以使用Wireshark查看您的网络流量,以查看客户端是否在做您期望的事情。

Charlie,
有几件事:

1) 如果FD_ISSET()在文件描述符上返回true,您可能应该循环使用select()调用并仅调用recvfrom。
2) 确保在netlink套接字上发送的实际驱动程序或内核代码实际上正在向其写入/发送数据。如果没有,那么如果函数在1秒内没有接收到数据,它将超时。(这就是您设置的超时)

一些一般性的评论。。。 在Linux中,当使用select()系统调用时。超时数据结构在每次调用后都会重置,因此如果您将代码更改为循环选择,您可能应该。。您必须为循环中的每个迭代重置超时值

此外,如果select超时,并不一定意味着这是一个错误。记住,select是一个非阻塞调用。它只需在套接字上等待给定的“超时”时间,然后返回。如果您想从文件描述符中读取任何内容。。。这意味着您希望您的recv_kern()函数阻塞,直到有数据返回为止,然后不用麻烦使用select()。只需直接在文件描述符上调用recvfrom()。这样,recv_kernel()函数将阻塞,并且仅在读取内核发送的数据后返回


在这里很难提供更具体的帮助,而不了解更多关于如何使用此代码的上下文。我假设这是您编写的一个自定义内核模块,它将数据发送到用户空间,对吗?
尝试将recv_kern()函数更改为block(去掉select代码,只需调用recvfrom()。这种方法应该能够判断内核驱动程序是否正确地向用户空间发送数据。如果您在recvfrom()上阻塞,并且没有任何结果返回。。那么您的内核驱动程序也可能有问题。

希望能有帮助。

查理,
有几件事:

1) 如果FD_ISSET()在文件描述符上返回true,您可能应该循环使用select()调用并仅调用recvfrom。
2) 确保在netlink套接字上发送的实际驱动程序或内核代码实际上正在向其写入/发送数据。如果没有,那么如果函数在1秒内没有接收到数据,它将超时。(这就是您设置的超时)

一些一般性的评论。。。 在Linux中,当使用select()系统调用时。超时数据结构在每次调用后都会重置,因此如果您将代码更改为循环选择,您可能应该。。您必须为循环中的每个迭代重置超时值

此外,如果select超时,并不一定意味着这是一个错误。记住,select是一个非阻塞调用。它只需在插座上等待给定的时间