我是一名新手网络编程,已经花费了相当长的时间来理解这个问题。在浏览了互联网上无数的资源之后,我得出了以下结论,接着是我的困惑。
结论1: 当我们谈到创建一个套接字时:
s = socket(AF_INET, SOCK_RAW, 0);
我们基本上是要创建一个原始套接字。通过这种方式创建的原始套接字可以绕过OSI堆栈中的TCP/UDP层。也就是说,当应用程序通过此套接字接收数据包时,该应用程序将拥有包含网络层(第3层)头部包装实际数据的第2层头部的数据包。因此,应用程序可以自由地处理此数据包,超越第3层,并以任何方式进行处理。
同样,当通过此套接字发送数据包时,应用程序也可以自由处理数据包的创建,直到第4层,然后将其传递到第3层,从此处开始内核将处理事务。
结论2:当我们谈论创建套接字时:
s = socket(AF_PACKET, SOCK_RAW, 0);
我们再次尝试创建一个原始套接字。通过这种方式创建的原始套接字将能够完全绕过OSI的所有层。用户应用程序可以获得纯粹的原始数据包,并且可以自由地对该数据包进行任何操作。通过这样的套接字接收到的数据包将保留所有标头,应用程序也可以访问所有这些标头。
同样,在使用这样的套接字发送数据时,用户应用程序需要处理有关创建数据包以及将实际数据与每个层的标头包装起来的所有内容,然后才能将其放置在物理介质上进行传输。
结论3:当我们谈论创建套接字时:
s = socket(AF_PACKET, SOCK_DGRAM, 0);
我们再次尝试创建原始套接字。通过这种方式创建的原始套接字,可以绕过OSI堆栈中的数据链路层(第2层)。也就是说,当用户应用程序接收到此类套接字上的数据包时,数据链路层头从数据包中删除。
同样,在通过此套接字发送数据包时,根据sockaddr_ll目标地址中的信息,添加适当的数据链路层头部到数据包中。
现在以下是我的疑问/困惑点:
- 我上面得出的有关原始套接字的结论是正确的吗?
- 我没有很清楚地理解上面的 结论3。可以有人解释一下吗?比如,它是否意味着当用户应用程序通过此套接字接收数据包时,只有内核处理了数据链路层标头?因此,数据包将类似于直接包裹第3层标头的消息,并随后由其上面的层次包裹?
- 如果上面得出的结论是正确的,则 结论1 和 结论2 仍然有意义。但是,如果上面的 结论3(以及2中围绕它的推测)是正确的,那么任何应用程序何时需要这样做呢?
我参考了一些资源来理解上述内容:
https://docs.freebsd.org/44doc/psd/21.ipc/paper.pdf
https://sock-raw.org/papers/sock_raw
https://www.quora.com/in/Whats-the-difference-between-the-AF_PACKET-and-AF_INET-in-python-socket
http://www.linuxcertif.com/man/7/PF_PACKET/
http://opensourceforu.com/2015/03/a-guide-to-using-raw-sockets/
{{link1:'socket'系统调用中的'SOCK_RAW'选项}}
http://stevendanna.github.io/blog/2013/06/23/a-short-sock-raw-adventure/