注:标题中的”(上)“,”(下)“表示分析过程基于数据包的传递方向:”(上)“表示分析是从底层向上分析、”(下)“表示分析是从上向下分析。
上篇分析了应用层经过BSD socket层到INET socket层的函数调用关系和数据的处理流程,INET层会调用具体的传输层协议,还是以UDP协议为例
udp_write()函数
static int udp_write(struct sock *sk, unsigned char *buff, int len, int noblock, unsigned flags) { return(udp_sendto(sk, buff, len, noblock, flags, NULL, 0)); } |
在分析udp_sendto()函数之前,先了解一下sockaddr_in结构,这是标准的网络接口地址结构的定义
struct sockaddr_in { short int sin_family; /* Address family 地址族 */ unsigned short int sin_port; /* Port number 端口号 */ struct in_addr sin_addr; /* Internet address 网络地址 */
/* Pad to size of `struct sockaddr'. */ unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) - sizeof(unsigned short int) - sizeof(struct in_addr)]; }; #define sin_zero __pad /* for BSD UNIX comp. -FvK */ |
udp_sentdto()函数
static int udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock, unsigned flags, struct sockaddr_in *usin, int addr_len) { struct sockaddr_in sin; int tmp;
/* * Check the flags. We support no flags for UDP sending */ if (flags&~MSG_DONTROUTE) return(-EINVAL); /* * Get and verify the address. */ if (usin) //如果usin不是空 { if (addr_len < sizeof(sin)) return(-EINVAL); memcpy(&sin,usin,sizeof(sin)); if (sin.sin_family && sin.sin_family != AF_INET) return(-EINVAL); if (sin.sin_port == 0) return(-EINVAL); } else //usin为空 { if (sk->state != TCP_ESTABLISHED) return(-EINVAL); sin.sin_family = AF_INET;//协议族 sin.sin_port = sk->dummy_th.dest;//目的端口 sin.sin_addr.s_addr = sk->daddr;//目的地址 } /* * BSD socket semantics. You must set SO_BROADCAST to permit * broadcasting of data. */ if(sin.sin_addr.s_addr==INADDR_ANY)//目的地址是全0地址,对应当前主机 sin.sin_addr.s_addr=ip_my_addr();//将目的地址设为当前主机的网络地址 if(!sk->broadcast && ip_chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST) return -EACCES; /* Must turn broadcast on first */
sk->inuse = 1;
/* Send the packet. */ tmp = udp_send(sk, &sin, from, len, flags);//调用udp_send()真正的发送数据
/* The datagram has been sent off. Release the socket. */ release_sock(sk); return(tmp); } |