linux socket 绑定机制的研究

linux socket 绑定机制的研究

 

 

 

1.    概述:

在多 link 环境中,如何保证数据在正确的 link 上传输是一个棘手的问题。

本文主要分析 linux socket 绑定机制的实现,从而帮助开发人员更好的了解 socket 绑定的本质。

2.    linux kernel 提供给 user space 的接口

linux 提供一个新的 setsockopt() 选项 SO_BINDTODEVICE 作为 user space 的接口。

 

源码:net/core/sock.c:

在编译内核的时候,必须打开 CONFIG_NETDEVICES 选项,否则 SO_BINDTODEVICE 不起作用;

struct sock 结构中,专门有一个域 bound_dev_if;在调用 setsockopt() 后,bound_dev_if 被设置为所绑定的 interface index bound_dev_if 将会影响后续的数据包的发送和接收。

sk->bound_dev_if = dev->ifindex;

 

socket 绑定之所以能保证数据在所绑定的 interface 上传输,是因为 linux 在路由选择的时候,需要考虑 socket 所绑定的interface(也就是 sock->bound_dev_if)。下面从发送和接收数据两个方面来分析这种影响:

 

3.    socket 绑定对发送数据包的影响

源码:include/net/route.h

              net/ipv4/route.c

 

影响1

任何传输层协议,最终都要走到 ip_route_output() 进行路由选择,linux 是根据 socket 的源地址、目的地址、TOS值以及所绑定的 interface(如果有)作为关键字进行路由查找的。因此,在 socket 绑定情况下,如果一个路由项的源地址、目的地址、TOS 都和 socket 匹配,但是 out interface socket 所绑定的 interface 不一致,那么该路由项也不会被选中。

这也正是绑定的意义所在:必须保证数据包被路由到所绑定的 interface 上。

影响2

socket 绑定对发送数据的路由选择的另一个重要影响是:即使在 route cache route table 中都查不到路由,该数据包仍然会被送到所绑定的 interface 上。具体代码在ip_route_output_slow() 中。

 

4.    socket 绑定对接收数据包的影响

源码:net/ipv4/ip_input.c

       Net/ipv4/tcp_ipv4.c

       Net/ipv4/udp.c

 

接收数据包需要在 ip_route_input() 中进行路由选择,socket 绑定对此阶段没有影响。

路由以后,到本地的包走到ip_local_deliver()ip_local_deliver_finish(),此后,根据传输层协议的不同,分别走到tcp_v4_rcv() udp_rcv()

这两个函数都首先需要找到该数据包所对应的 struct sock 结构:

       tcp_v4_rcv()  在查找sock 时,会严格检查 sock bound_dev_if 与数据包进来的 interface 是否一致,如果两者不一致,则该 sock 不会被匹配。

udp_rcv() 在查找 sock 时,也检查这两个值是否匹配(具体代码在udp_v4_lookup_longway()中),但是就算不匹配,也可能接收这个包,原因是 UDP 相对于 TCP 来说,在一致性检查上没有那么严格。它的策略是:在源地址、目的地址、目的端口、绑定的 interface 四项检查中,寻找匹配程度最高的那个 sock  

5.    socket 绑定使用时候的注意事项

不要将一个 socket 绑定到多个不同的 interface 上,这样会导致不可预料的后果。因为当你第一次绑定到一个interface 上发送数据后,在 route cache 中将会保存一个路由项,如果此时将该 socket 绑定到另一个 interface,那么从前一个 interface 上回来的数据包在路由的时候,就可能查不到对应的 socket ,从而被丢弃。

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
你可以使用UNIX域套接字(UNIX domain socket)来实现在Linux上进行C语言广播而不绑定套接字信息。UNIX域套接字是一种在本地进程之间进行通信的机制,不需要绑定到网络接口。 下面是一个简单的示例代码,展示了如何在C语言中使用UNIX域套接字进行广播: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #define SOCKET_PATH "/tmp/my_socket" int main() { int sockfd; struct sockaddr_un addr; // 创建UNIX域套接字 sockfd = socket(AF_UNIX, SOCK_DGRAM, 0); if (sockfd == -1) { perror("socket"); exit(EXIT_FAILURE); } // 设置套接字地址 memset(&addr, 0, sizeof(struct sockaddr_un)); addr.sun_family = AF_UNIX; strncpy(addr.sun_path, SOCKET_PATH, sizeof(addr.sun_path) - 1); // 发送广播消息 const char* message = "Hello, world!"; if (sendto(sockfd, message, strlen(message), 0, (struct sockaddr*)&addr, sizeof(struct sockaddr_un)) == -1) { perror("sendto"); exit(EXIT_FAILURE); } // 关闭套接字 close(sockfd); return 0; } ``` 在上面的示例中,我们创建了一个UNIX域套接字(`socket`函数),将其地址设置为`/tmp/my_socket`(`struct sockaddr_un`),然后使用`sendto`函数发送广播消息。 请注意,该示例代码只发送广播消息,并没有绑定到特定的套接字信息。如果其他进程在同一台机器上监听相同的UNIX域套接字地址,它们将能够接收到这个广播消息。 希望这可以帮助到你!如果有任何进一步的问题,请随时问我。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值