在Linux中,Ubuntu 14.04: 我正在编写一个实现套接字的代码来发送包含UDP头+有效负载的纯UDP数据报,而不包含任何IP头部分。
我创建了套接字
sokt_fd=socket(AF_INET, SOCK_RAW, IPPROTO_UDP)
另外,我准备了UDP标头。
我想将IP封装过程留给内核。
我想通过任何可用的IP接口发送数据报。 (我不想指定源IP,也将此任务留给内核)。
在发送数据报之前是否需要指定目标IP地址。
我必须使用" 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
};
答案 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_datagram
和datagram_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;
htons
和htonl
分别代表“主机到网络(短)”和“主机到网络(长)”。你需要这个,因为有一段时间网络驱动程序太愚蠢,无法抽象出机器的字节序,我们无法及时回过头来修复它们。 (网络字节顺序是大端。)