2016-02-05 73 views
-1

我正在嘗試使用編寫客戶端/服務器應用程序RAW套接字。原始套接字:sendto()和recvfrom()不工作

有多種問題:

  1. 當客戶端將消息發送到使用SENDTO服務器()方法,誤差無效參數SENDTO()返回方法。 爲什麼會出現此錯誤訊息?。相應的代碼在錯誤1部分標記。 sendto()的代碼在這篇文章中有評論。

  2. 由於我已經評論了發送消息部分,客戶端應等待消息; recvfrom()是阻止系統調用。相反,recvfrom()總是返回消息E此消息來自哪裏?。相應的代碼被標記爲錯誤2

  3. 如果我在插座()到或IPPROTO_RAW改變協議(3日)的說法,我得到協議不受支持的錯誤。爲什麼會出現這些錯誤?

操作系統是Ubuntu的

#include <stdio.h> 
    #include <stdlib.h> 
    #include <unistd.h> 

    #include <sys/socket.h> // For the socket() etc. functions. 
    #include <netinet/in.h> // For IPv4 data struct.. 
    #include <string.h>  // For memset. 
    #include <arpa/inet.h> // For inet_pton(). 

    #define BUF_SIZE 30 

    void main() 

    { 
     int rst; // Return status of functions. 
    /**************** Create a socket. *******************************/ 
    int sfd; // Socket file descriptor. 
    sfd = socket (AF_INET, SOCK_RAW, IPPROTO_UDP); /* 
      * AF_INET --> IPv4, SOCK_RAW for Raw socket, 
      * 0 --> for any protocol. */ 
    if (sfd == -1) 
    { 
     perror ("Client: socket error"); 
     exit (1); 
    } 


    /*********** Server's address ***********************************/ 
    struct sockaddr_in srv_addr; 
    socklen_t addrlen = sizeof (struct sockaddr_in); 

    // Initializing the server's address to zero. 
    memset (&srv_addr, 0, addrlen); 

    srv_addr.sin_family = AF_INET; // Address is in IPv4 format. 
    // srv_addr.sin_port = htons (0); // Port number of the server. 


    rst = inet_pton (AF_INET, "127.0.0.1", &srv_addr.sin_addr); /* Note 
      * that third field should point to an in_addr (in6_addr). */ 
    if (rst <= 0) 
    { 
     perror ("Client Presentation to network address conversion.\n"); 
     exit (1); 
    }   



    /****************** ERROR 1 ************************************ 
    ******************* Sending message to the server. *************/ 
    const int flags = 0; 
    const char *msg = "Hello"; 
    /* rst = sendto (sfd, msg, strlen(msg)+1, flags, 
        (struct sockaddr *) &srv_addr, 
        sizeof (struct sockaddr_in)); 
    if (rst < 0) 
    { 
     perror ("Client: Sendto function call failed"); 
     exit (1); 
    } 
    else 
     printf ("Client: Sent data size = %d\n", rst); 

    */ 


    /******************* ERROR 2 *********************************** 
    ******************* Receiving message from server. ************/ 
    // Initializing the server's address to zero. 
    memset (&srv_addr, 0, addrlen); 

    char buf[BUF_SIZE] = {'\0'}; 

    rst = recvfrom (sfd, buf, BUF_SIZE, flags, 
        (struct sockaddr *) &srv_addr, 
        &addrlen); 
    if (rst < 0) 
    { 
     perror ("Client: couldn't receive"); 
     exit (1); 
    } 
    printf ("Message from server = |%s|\n", buf); 

    /* Address of the server. */ 
    const char *buf2 = inet_ntop (AF_INET, 
         (struct sockaddr *) &srv_addr, buf, BUF_SIZE); 
    if (buf2 == NULL) 
    { 
     perror ("Client: Conversion of sender's address to presentation failed"); 
     exit (1); 
    } 

    printf ("Servers address, = %s\n", buf2); 
    close (sfd); 

} 
+0

您的「錯誤1」對我來說工作正常。如果您需要進一步的調試幫助,您可以使用strace工具運行程序併發布輸出。請記住,原始套接字接收您的機器接收到的每個IP數據包。也許你正在收到一個DNS或SSH數據包等等,你打印出來的'E'是IP頭的1.字節。 IPv4數據包中的1個字節是0x45,在ASCII中被解釋爲E。所以,請記住,由於您使用RAW套接字,您也正在接收IP標頭。如果您使用IPPROTO_RAW,則需要創建您發送的有效IP標頭。 – nos

回答

0

SOCK_RAW不適用於UDP。 SOCK_DGRAM是正確的。對於一個教程,請參閱:

a tutorial from Rutgers

+0

我需要使用** RAW套接字**。 ** IPPROTO_UDP **需要更改爲** IPPROTO_RAW **。但正如**第3點**所述,它會產生_Invalid Protocol_錯誤。 –

+1

原始套接字接受原始IP數據包而不是字符串。 – bmargulies

0

編輯:忽略了srv_addr的初始化...對不起。

使用AF_INET + SOCK_RAW套接字,你可以發送任何東西 - 有效載荷只是添加在IP層的頂部。 IPPROTO_UDP只是告訴內核下一層將會是什麼(你的有效載荷被添加到的層)以及IP頭的協議字段必須設置爲哪個值。所以要保存(如果你去發送原始數據)將協議設置爲不常用的東西)。

您需要創建原始套接字的權限。這通常意味着:以root身份啓動,創建套接字然後刪除權限。

q2:這是您發送給自己的消息(並強烈表明您的代碼以某種方式工作)。 'E'只是IP頭中的第一個字節(0x45) - 版本4和頭部長度5.只是轉儲整個緩衝區...,例如。

printf ("Message from server = |"); 
    for (i = 0; i < rst; i++) 
     printf("%c", isprint(buf[i]) ? buf[i] : '?') ; 
printf ("|\n"); 

Q3:

指:猜測,通常使用(例如INET + DGRAM - > TCP)。正如你指定的raw內核不能爲下一層選擇一個通用協議。

IPPROTO_RAW應該可以工作(請參閱@nos的評論)

+1

套接字(AF_INET,SOCK_RAW,IPPROTO_RAW)應該可以工作,它只是向下移動一層,如文檔[這裏](http://manpages.ubuntu.com/manpages/wily/en/man7/raw.7.html) – nos

+0

justed檢查它 - 你是對的。 – hecke