2009-05-05 68 views
1

我有一個功能,正如這一點: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

回答

1

不相關的超時時間,但你FD_SET(襪子,&集)之前需要FD_ZERO(&集),否則FD_SET將未初始化的並且很可能包含許多設置位。另外,退出之前的FD_ZERO()是毫無意義的。

+0

你說的是不是原因,我已經根據你的指示改變我的代碼,但它不起作用,謝謝你們一樣。 – 2009-05-05 02:22:47

0

我在內核空間研究我的代碼,我知道內核無法使用方法「skb_dequeue(& sk-> sk_receive_queue)」從客戶端接收消息。 我不知道它是如何發生的。

+0

這不應該是一個答案,它應該是你的問題的編輯。 – ffledgling 2013-03-20 14:20:24

0

對於初學者來說,你可以找出什麼是打印出strerror(errno)實際的錯誤(錯誤號的印刷也是明智)時發生超時。

至於猜測的問題可能是在沒有錯誤號是什麼,請注意,沒有保證說有什麼閱讀;即使你通過accept(2)獲得套接字,也可能只是建立了一個連接,但客戶卻沒有寫信給它。通常你不會做一個選擇(2);你希望有一個主循環繼續調用select(2),直到程序想要退出,因爲幾乎任何時候任何原因都可能發生超時。

其他可能出現的問題:

  • 客戶端無法連接。
  • 您無法正確地綁定套接字。
  • 調用bind(2)後,您忘記在服務器的套接字上調用listen(2)。

如果您使用IP套接字,您可以使用Wireshark查看您的網絡流量,以查看客戶端是否在按照您的預期行事。

4

查理,
幾件事情:

1)你或許應該在你的select()調用循環,並只調用recvfrom的,如果FD_ISSET()在你的文件描述符返回true。
2)確保在netlink套接字上發送的實際驅動程序或內核代碼實際上正在向其寫入/發送數據。如果不是,那麼如果它在1秒內沒有收到數據,你的功能將超時。 (這是你設置的超時時間)。

一對夫婦的一般性評論... 在Linux中,使用select()系統調用時。在每次調用之後,超時數據結構都會被重置,所以如果您將代碼更改爲循環選擇,您可能應該......您必須重置循環中每次迭代的超時值。

而且,如果選擇超時,這並不一定意味着它是一個錯誤。請記住,select是非阻塞呼叫。它只會在給定的「超時」期間等待套接字並返回。如果你想從文件描述符中讀取,不管...這意味着你希望你的recv_kern()函數阻塞,直到有數據返回,那麼不要打擾使用select()。直接在文件描述符上調用recvfrom()。這樣你的recv_kernel()函數就會被阻塞,並且只有在讀取內核發送的數據後纔會返回。


這裏很難給出更具體的幫助,而不瞭解更多關於如何使用這段代碼的上下文。我假設這是你寫的一個定製的內核模塊,它將數據發送到用戶空間,是否正確?
嘗試更改您的recv_kern()函數以阻止(選擇代碼並調用recvfrom())。這種方式應該能夠告訴你的內核驅動程序是否實際上正確地向用戶空間發送數據。如果你在recvfrom()上阻塞,並且沒有任何東西會回來,那麼你的內核驅動程序也可能有問題。

希望有所幫助。

2

你應該重寫這樣的功能:

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的其他調用是多餘的。此外,你需要做全面的錯誤檢查。