原始套接字:sendto()和recvfrom()不工作

问题描述:

我正在尝试使用编写客户端/服务器应用程序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

SOCK_RAW不适用于UDP。 SOCK_DGRAM是正确的。对于一个教程,请参阅:

a tutorial from Rutgers

+0

我需要使用** RAW套接字**。 ** IPPROTO_UDP **需要更改为** IPPROTO_RAW **。但正如**第3点**所述,它会产生_Invalid Protocol_错误。 –

+1

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

编辑:忽略了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