Linux套接字编程调试?

问题描述:

我有一个功能,正如这一点:Linux套接字编程调试?

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

其用于使用网络链路从内核空间接收消息。但是当我运行它的时候,结果总是说源代码中的“从内核收回答案时超时”的消息,这是由于“select”方法总是返回“0”的原因造成的。我不知道原因,谁能给我一些建议,谢谢。

+0

也许你创建套接字有什么问题?或者做了一个绑定到套接字?为了创建netlink套接字,你应该使用套接字(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE);并绑定你应该指定一个地址与结构sockaddr_nl和成员nl_family = AF_NETLINK。 – 2009-05-05 02:00:15

+0

是的,我已经照你所说的去做了。 – 2009-05-05 02:15:26

+0

只要先做recvfrom并让它工作正常。一旦你确定你的套接字工作正常,做你的选择的东西 – shodanex 2009-06-17 13:12:42

不相关的超时时间,但你FD_SET(袜子,&集)之前需要FD_ZERO(&集),否则FD_SET将未初始化的并且很可能包含许多设置位。另外,退出之前的FD_ZERO()是毫无意义的。

+0

你说的是不是原因,我已经根据你的指示改变我的代码,但它不起作用,谢谢你们一样。 – 2009-05-05 02:22:47

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

+0

这不应该是一个答案,它应该是你的问题的编辑。 – ffledgling 2013-03-20 14:20:24

对于初学者来说,你可以找出什么是打印出strerror(errno)实际的错误(错误号的印刷也是明智)时发生超时。

至于猜测的问题可能是在没有错误号是什么,请注意,没有保证说有什么阅读;即使你通过accept(2)获得套接字,也可能只是建立了一个连接,但客户却没有写信给它。通常你不会做一个选择(2);你希望有一个主循环继续调用select(2),直到程序想要退出,因为几乎任何时候任何原因都可能发生超时。

其他可能出现的问题:

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

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

查理,
几件事情:

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

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

而且,如果选择超时,这并不一定意味着它是一个错误。请记住,select是非阻塞呼叫。它只会在给定的“超时”期间等待套接字并返回。如果你想从文件描述符中读取,不管...这意味着你希望你的recv_kern()函数阻塞,直到有数据返回,那么不要打扰使用select()。直接在文件描述符上调用recvfrom()。这样你的recv_kernel()函数就会被阻塞,并且只有在读取内核发送的数据后才会返回。


这里很难给出更具体的帮助,而不了解更多关于如何使用这段代码的上下文。我假设这是你写的一个定制的内核模块,它将数据发送到用户空间,是否正确?
尝试更改您的recv_kern()函数以阻止(选择代码并调用recvfrom())。这种方式应该能够告诉你的内核驱动程序是否实际上正确地向用户空间发送数据。如果你在recvfrom()上阻塞,并且没有任何东西会回来,那么你的内核驱动程序也可能有问题。

希望有所帮助。

你应该重写这样的功能:

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

像别人说的,你需要调用select之前调用FD_ZERO。对FD_ZERO的其他调用是多余的。此外,你需要做全面的错误检查。