"仅限UDP数据报" C中的套接字

时间:2015-01-04 11:48:38

标签: c linux network-programming

在Linux中,Ubuntu 14.04: 我正在编写一个实现套接字的代码来发送包含UDP头+有效负载的纯UDP数据报,而不包含任何IP头部分。

我创建了套接字

sokt_fd=socket(AF_INET, SOCK_RAW, IPPROTO_UDP)

另外,我准备了UDP标头。

  1. 我想将IP封装过程留给内核。

  2. 我想通过任何可用的IP接口发送数据报。 (我不想指定源IP,也将此任务留给内核)。

  3. 在发送数据报之前是否需要指定目标IP地址。

  4. 我必须使用" sendto()"命令发送数据报;我怎么必须填补" sockaddr"数据结构?

    #include <netinet/in.h>
    struct sockaddr
    {
        unsigned short    sa_family;// address family, AF_xxx
        char              sa_data[14];// 14 bytes of protocol address
    };
    

3 个答案:

答案 0 :(得分:1)

不要使用sockaddr结构。当您必须将sockaddr_in传递给函数时,请使用sockaddr*并投射它。

struct sockaddr_in myaddr;
int s;

myaddr.sin_family = AF_INET;
myaddr.sin_port = htons(3490);
inet_aton("63.161.169.137", &myaddr.sin_addr.s_addr);

s = socket(PF_INET, SOCK_STREAM, 0);
bind(s, (struct sockaddr*)myaddr, sizeof(myaddr));

套接字API专为不同的寻址系列而设计,其他则是红外线和蓝牙。由于AF_INET只是其中一个系列,因此API函数在参数中使用通用sockaddr类型。

答案 1 :(得分:0)

第3章中有一个很好的解释,&#34;套接字简介&#34;在Richard Stevens等着名的书籍 Unix网络编程,套接字网络API (第1卷)中。人。我来引用一下:

  

大多数套接字函数都需要指向套接字地址结构的指针   作为一个论点。每个支持的协议套件定义自己的套接字   地址结构。这些结构的名称始于   sockaddr_并以每个协议套件的唯一后缀结束。

对于IP(Internet协议)套件,结构为sockaddr_in因此,由于您的示例在创建套接字时指定了AF_INET地址系列,因此您将使用更具体的sockaddr_in结构而不是更通用的sockaddr。作为效率问题,套接字API使用签名原型中更通用的sockaddr指针。

关于使用send()sendto(),我发现sendto()更常用于UDP,send()使用TCP套接字。因此,要回答上面#3中的问题,使用UDP,您不必预先指定目标地址,而是将其作为sendto()的参数提供。

对于给定的udp_datagramdatagram_length,您的代码可能如下所示:

uint32_t       address = inet_addr("1.2.3.4");   // can also provide hostname here
uint16_t       port    = 27890;
sockaddr_in_t  dest_addr;
memset(*dest_addr, 0, sizeof(dest_addr));

dest_addr.sin_family = AF_INET;
dest_addr.sin_port   = htons(port);
dest_addr.sin_addr.s_addr = htonl(address);

sendto(socket_fd, 
       (const char*)upd_datagram, 
       datagram_length,
       0,
       reinterpret_cast<sockaddr_t*>(&dest_addr),
       sizeof(dest_addr));

答案 2 :(得分:0)

地址API确实想要面向对象,但必须处理C不是OO语言的事实。 sockaddr可以被视为“基类”,并且在需要地址时使用绑定,连接,发送,接收等参数类型。但是,您必须提供与您正在使用的套接字域匹配的“子类”地址。这是因为Berkeley套接字可用于广泛且可扩展的协议范围。 IPv4和IPv6是最典型的,但基于UNIX的安装也支持套接字作为文件系统对象(由路径“寻址”),例如,管理程序驱动程序可以安装对特殊VM间或客户机到主机套接字的支持。有关概述,请参阅man 7 socket

如果您使用IPv4,则需要使用sockaddr_in。如果您使用IPv6,则需要使用sockaddr_in6。在这两种情况下,您都需要将指针转换为sockaddr*

要填写sockaddr_in,您需要执行以下操作:

struct sockaddr_in inet_addr;
inet_addr.sin_family = AF_INET;
inet_addr.sin_port = htons(port);
inet_addr.sin_addr.s_addr = htonl(ip_address_as_number);
struct sockaddr* addr = (struct sockaddr*)&inet_addr;

htonshtonl分别代表“主机到网络(短)”和“主机到网络(长)”。你需要这个,因为有一段时间网络驱动程序太愚蠢,无法抽象出机器的字节序,我们无法及时回过头来修复它们。 (网络字节顺序是大端。)