inet_sock 源地址,目的地址, 接收地址,端口

http://www.cnblogs.com/my_life/articles/6085516.html

http://www.cnblogs.com/my_life/articles/6085588.html

http://www.cnblogs.com/my_life/articles/6065752.html

https://www.cnblogs.com/my_life/articles/6085848.html

./include/net/inet_sock.h   :inet_sock

./net/ipv4/af_inet.c     :inet_bind

108 struct inet_sock {         
114     /* Socket demultiplex comparisons on incoming packets. */                                                            
115     __u32           daddr;     //Foreign IPv4 addr,socket将要连接的外部地址
116     __u32           rcv_saddr;    //Bound local IPv4 addr, rcv_saddr is the one used by hash lookups。对于组播而言,只接收该地址发来的组播数据;对于单播而言,只从该地址所代表的网卡接收数据
117     __u16           dport;    //Destination port
118     __u16           num;     //Local port,为用户提供的端口,不可用,出错;可用,sport = num;
119     __u32           saddr;   //Sending source, saddr is used for transmit,通过该地址找到对应的发送网卡来发送数据

***     __u16           sport;    //Source port

 

  • 对于bind()操作而言,是为了绑定本地地址和端口,所以其

inet->daddr = 0;
inet->dport = 0;    //无需连接外部地址

 

inet->inet_rcv_saddr = inet->inet_saddr = addr->sin_addr.s_addr;    //查找地址和发送地址为用户的设置

 

 /*  若地址类型为广播或多播,则将地址置 0,表示直接使用网络设备 */ 
 if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST)   //是根据地址解析出来的
   inet->saddr = 0;  /* Use device */ 

 //例如对于组播而言,其saddr由setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, &addr, sizeof(addr))来设置源地址、发送地址、由哪个网卡发送。不调用该选项的话,使用系统默认的网卡发送组播数据。

 //setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq))来设置接收地址,由哪个网卡接收

 

snum = ntohs(addr->sin_port);    //用户空间指定的端口

get_port(sk, snum)   //确认是否可绑定端口. 若可以, 则绑定在 inet->num 之上;不可用出错

inet->sport = htons(inet->num);

若绑定了端口,则发送和接收都使用该端口

==========================================================================

IP_MULTICAST_IF
  作用似乎跟bind()有些重复。对于单播的时候,有inet_sock的成员rcv_saddr==saddr(本地发送数据用到的地址=本地接收数据
的地址),当用于组播时,saddr等于0(即本地发送数据地址为0),此时不知道用哪个地址发送数据,这个任务就留给了IP_MULTICAST_IF选项。
要有接收组播数据工能时,bind()不是邦写本地主机的IP,而是邦定组播组的IP。也就是说要接收到组播组发送的数据,还得把本地的IP信息提供上去,此时就用到IP_MULTICAST_IF。

==========================================================================

对于 TCP 协议来说,其连接实际上就是发送一个 SYN 报文,在服务器的应答到来时,回答它一
个 ack 报文,也就是完成三次握手中的第一和第三次。 
 
要发送 SYN 报文,也就是说,需要有完整的来源/目的地址,来源/目的端口,目的地址/端口由用户
态提交,但是问题是没有自己的地址和端口,因为并没有调用过 bind(2),一台主机,对于端口,
可以像 sys_bind()那样,从本地未用端口中动态分配一个,那地址呢?因为一台主机可能会存在多
个 IP地址,如果随机动态选择,那么有可能选择一个错误的来源地址,将不能正确地到达目的地
址。换句话说,来源地址的选择,是与路由相关的。 
 
调用路由查找的核心函数 ip_route_output_slow(),在没有提供来源地址的情况下,会根据实际情况,
调用 inet_select_addr()函数来选择一个合适的。同时,如果路由查找命中,会生成一个相应的路由
缓存项,这个缓存项,不但对当前发送SYN报文有意义,对于后续的所有数据包,都可以起到一
个加速路由查找的作用。这一任务,是通过 ip_route_connect()函数完成的,它返回相应的路由缓存
项(也就是说,来源地址也在其中了)。

 

int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) 
{

  nexthop = daddr = usin->sin_addr.s_addr; //        将下一跳地址和目的地址的临时变量都暂时设为用户提交的地址。  

  tmp = ip_route_connect(&rt, nexthop, inet->saddr,    
                               RT_CONN_FLAGS(sk), sk->sk_bound_dev_if, 
                               IPPROTO_TCP, 
                               inet->sport, usin->sin_port, sk);     //如果之前进行了bind(),则sport为bind()提供的端口,否则使用动态选择的端口

 

  if (!inet->opt || !inet->opt->srr) 
                daddr = rt->rt_dst;   //        更新目的地址临时变量——使用路由查找后返回的值。 

 

  if (!inet->saddr) 
                inet->saddr = rt->rt_src; 
      inet->rcv_saddr = inet->saddr;   //        如果还没有设置源地址,和本地发送地址,则使用路由中返回的值。 

  inet->dport = usin->sin_port;     //dport为用户提供的目的端口
      inet->daddr = daddr;    //     保存目的地址及端口 

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值