20100201 链路层协议通信sokect方式 1(转)

来源:互联网 发布:软件行业数据 编辑:程序博客网 时间:2024/05/20 10:24

通过PF_PACKET创建socket的时候,其中第三个参数protocol(socket(PF_PACKET, type, protocol))的值可以指定为ETH_P_ALL/ ETH_P_ARP/ ETH_P_IP/ 0。

 

1. 指定为0的时候,表示所创建的socket并不监听任何报文;

2. 指定为 ETH_P_ALL的时候,表示监听所有报文;

3. 指定为ETH_P_ARP的时候,表示监听ARP报文;

4. 指定为ETH_P_IP的时候,表示监听IP报文。

 

当创建这种类型的socket时,如果主要目的不是为了监听报文而是发送自己组装的报文,那么protocol的取值就变得不重要了。也就是说,如果纯粹的使用PF_PACKET类型的socket来进行报文发送的时候,这几个取值之间没有任何的本质区别。

 

用户程序在提交发送数据给内核以前 (sendto),必须完整的填写以太网头部,ARP头部及其数据(ARP报文),IP头部及其数据(IP报文)等等,并且其正确性和有效性也需要由应用程序来进行保证,内核是不会干预其中的内容,除了添加以太网的CRC以及发送数据以外。 通过bind系统调用,也可以改变应用程序的接收行为(或者称为监听行为)。

 

如在创建PF_PACKET的socket的时候,protocol的参数被指定为ETH_P_ALL,而在调用bind的时候(绑定socket到网卡),传递的protocol参数为ETH_P_ARP,那么内核就会将应用程序的接收行为同时修改为ETH_P_ARP(只监听ARP报文)。

 

以下给出bind的例子:

struct sockaddr_ll sll;

sll.sll_family = AF_PACKET;==>必须指定为AF_PACKET

sll.sll_protocol = htons(ETH_P_ALL);

sll.sll_ifindex = if_index;==> 绑定网卡的编号

bind(socket, (struct sockaddr *)&sll, sizeof (struct sockaddr_ll));==>进行绑定

 

当调用bind的时候,protocol为0,那么内核就不会转发任何数据报文给该socket。在发送报文的时候,如果已经进行了网卡绑定,那么sendto系统调用的const struct sockaddr *to参数可以指定为NULL,其长度指定为0。const struct sockaddr *to一般在以下两种情况下会被使用。

1)没有进行网卡绑定

2)已经进行网卡绑定,但所发送的数据是给另外一个不同网卡的时候。