Wil*_*iam 8 c sockets linux ip raw-sockets
我在Linux机器上通过C中的原始套接字发送一些ping数据包.
int sock_fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
Run Code Online (Sandbox Code Playgroud)
这意味着我在写入套接字时指定了IP包头(IP_HDRINCL隐含).
写入套接字send失败,告诉我需要指定一个地址.
如果我使用sendto那么它的工作原理.对于sendto我必须指定一个sockaddr_in结构来使用,其中包括场sin_family,sin_port和sin_addr.
但是,我注意到了一些事情:
sin_family是AF_INET-创建插座时已经指定. sin_port自然是未使用的(端口不是IP的概念).sin_addr指定1.1.1.1)都无关紧要.似乎没有一个额外的字段在sendto很大程度上实际使用.那么,是否存在技术原因导致我必须使用sendto而send不仅仅是API中的疏忽?
ref*_*ind 11
写入套接字
send失败,告诉我需要指定一个地址.
它失败,因为send()功能只能用来连接插座(为说明这里).通常send()用于TCP通信(面向连接),sendto()可用于发送UDP数据报(无连接).
由于您要发送"ping"数据包,或者更准确地发送ICMP数据报(这些数据报明显无连接),您必须使用该sendto()功能.
似乎没有一个额外的字段在
sendto很大程度上实际使用.那么,是否存在技术原因导致我必须使用sendto而send不仅仅是API中的疏忽?
简短回答:
当你不被允许使用时send(),只剩下一个选项,叫做sendto().
答案很长:
这不仅仅是对API的疏忽.如果要使用普通套接字(例如SOCK_DGRAM)发送UDP数据报,sendto()需要有关结构中提供的目标地址和端口的信息sockaddr_in,对吗?内核会将该信息插入到生成的IP头中,因为struct sockaddr_in是您指定接收者的唯一位置.或者换句话说:在这种情况下,内核必须从结构中获取目标信息,因为您没有提供额外的IP标头.
因为sendto()它不仅用于UDP而且还用于原始套接字,它必须是或多或少的"通用"功能,它可以覆盖所有不同的用例,即使端口号之类的某些参数最终不相关/使用.
例如,通过使用IPPROTO_RAW(自动暗示IP_HDRINCL),您表明您想要自己创建IP标头.因此,最后两个参数sendto()实际上是冗余信息,因为它们已经包含在您传递给sendto()第二个参数的数据缓冲区中.请注意,即使您使用IP_HDRINCL原始套接字,如果将相应字段设置为,内核也会填写IP数据报的源地址和校验和0.
如果你想编写自己的ping程序,你也可以改变你的最后一个参数socket()的功能IPPROTO_RAW,以IPPROTO_ICMP让内核创建IP报头的你,让你有一个东西少操心.现在,你可以很容易地看到如何在两个sendto()α参数*dest_addr,并addrlen再次成为显著,因为这就是你提供的目的地地址的唯一地方.
语言和API非常陈旧,并且随着时间的推移而增长.从今天的角度看,有些API看起来很奇怪,但是如果不破坏大量现有代码,就无法更改旧接口.有时你只需要习惯几年或几十年前定义/设计的东西.
希望这能回答你的问题.