我试图使用原始套接字编写一些代码,而我发现了一些奇怪的现象。考虑一下代码:
int rsfd = socket(AF_INET,SOCK_RAW,253);
if(rsfd<0)
{
perror("Raw socket not created");
}
else
{
struct sockaddr_in addr2;
memset(&addr2,0,sizeof(addr2));
addr2.sin_family = AF_INET;
addr2.sin_addr.s_addr = inet_addr("127.0.0.2");
/* if(connect(rsfd,(struct sockaddr*)&addr2,sizeof(addr2))<0)
{
perror("Could not connect");continue;
} */
}
现在,如果我删除注释部分,我通过此rsfd发送的任何消息也将被自己接收。另一方面,我已经使用ip地址127.0.0.2
绑定了一个套接字。当我打印发送器套接字的IP地址时,它正在打印127.0.0.1
,但它仍在接收用于127.0.0.2
的数据包。当我添加评论部分中提到的连接请求时,此问题得以解决。这看起来很奇怪,因为另一方面,没有人接受或听取这个地址,而且,我使用sendto
和recvfrom
函数来发送和接收用于连接少套接字的数据包。我的问题是,为什么会发生这种情况?这个连接请求如何解决这个问题?
现在,如果我[不
connect()
套接字],我通过这个rsfd发送的任何消息也是自己收到的。
我首先注意到原始套接字是POSIX的扩展。 Linux提供了它们,我认为其他系统也是如此,但是它们的行为细节并不一定在各个实现中保持一致。
话虽如此,问题似乎可能是你不是bind()
ing你的套接字到任何地址。例如,在Linux上,the docs for raw sockets会注意到这一点
可以使用
bind(2)
调用将原始套接字绑定到特定的本地地址。如果未绑定,则接收具有指定IP协议的所有数据包。
(重点补充。)在原始套接字具有该行为的系统上,如果您通过既未绑定也未连接的原始IP套接字将数据包发送到IP环回地址,则是,源套接字将接收它们,或者至少可能会。
目前还不清楚为什么连接插座解决了问题,或者为什么它甚至都成功了。 connect()
的行为未指定除标准类型之外的套接字类型,SOCK_DGRAM
,SOCK_STREAM
和SOCK_SEQPACKET
。但是,您观察到的行为与connect()
一致,它对原始套接字有影响,就像它在数据报套接字上一样,它也是无连接的:
如果套接字
sockfd
的类型为SOCK_DGRAM
,那么addr
是默认发送数据报的地址,也是接收数据报的唯一地址。
但是,我建议不要依赖于发现的行为,而是遵循记录(至少在Linux上)将套接字绑定到地址(包括端口)并在该地址与之通信的过程。