Linux内核--网络栈实现分析(九)--传输层之UDP协议(下)
本文分析基于Linux Kernel 1.2.13
原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7549340
更多请查看专栏,地址http://blog.csdn.net/column/details/linux-kernel-net.html
作者:闫明
注:标题中的”(上)“,”(下)“表示分析过程基于数据包的传递方向:”(上)“表示分析是从底层向上分析、”(下)“表示分析是从上向下分析。
上篇分析了应用层经过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);
- }
udp_send()函数
- static int udp_send(struct sock *sk, //要发送的数据包使用的协议对用的sock结构
- struct sockaddr_in *sin,//目的端的标准的网络接口地址
- unsigned char *from,//要发送的数据所在地址
- int len,//发送数据的长度
- int rt)
- {
- struct sk_buff *skb;
- struct device *dev;
- struct udphdr *uh;
- unsigned char *buff;
- unsigned long saddr;
- int size, tmp;
- int ttl;
- /*
- * Allocate an sk_buff copy of the packet.
- */
- size = sk->prot->max_header + len;//计算大小为UDP最长表头+ 数据长度
- skb = sock_alloc_send_skb(sk, size, 0, &tmp);//根据要发送的数据分配sk_buff结构空间并对当前套接字状态检查
- if (skb == NULL)
- return tmp;
- skb->sk = NULL; /* to avoid changing sk->saddr */
- skb->free = 1;
- skb->localroute = sk->localroute|(rt&MSG_DONTROUTE);
- /*
- * Now build the IP and MAC header.
- */
- buff = skb->data;//将skb中的数据指针赋值给buff指针
- saddr = sk->saddr;//本地地址
- dev = NULL;
- ttl = sk->ip_ttl;//生存时间
- #ifdef CONFIG_IP_MULTICAST
- if (MULTICAST(sin->sin_addr.s_addr))
- ttl = sk->ip_mc_ttl;
- #endif
- tmp = sk->prot->build_header(skb, saddr, sin->sin_addr.s_addr,
- &dev, IPPROTO_UDP, sk->opt, skb->mem_len,sk->ip_tos,ttl);//调用ip_build_header()创建IP报头和调用ip_send()创建MAC首部
- skb->sk=sk; /* So memory is freed correctly */
- /*
- * Unable to put a header on the packet.
- */
- if (tmp < 0 )
- {
- sk->prot->wfree(sk, skb->mem_addr, skb->mem_len);
- return(tmp);
- }
- buff += tmp;
- saddr = skb->saddr; /*dev->pa_addr;*/
- skb->len = tmp + sizeof(struct udphdr) + len; /* len + UDP + IP + MAC */
- skb->dev = dev;
- /*
- * Fill in the UDP header. 填写UDP的报头
- */
- uh = (struct udphdr *) buff;
- uh->len = htons(len + sizeof(struct udphdr));//数据包长度
- uh->source = sk->dummy_th.source;//本地端口
- uh->dest = sin->sin_port;//远端端口
- buff = (unsigned char *) (uh + 1);
- /*
- * Copy the user data.
- */
- memcpy_fromfs(buff, from, len);//复制用户数据
- /*
- * Set up the UDP checksum.
- */
- udp_send_check(uh, saddr, sin->sin_addr.s_addr, skb->len - tmp, sk);//计算UDP报头的校验和
- /*
- * Send the datagram to the interface.
- */
- udp_statistics.UdpOutDatagrams++;
- sk->prot->queue_xmit(sk, dev, skb, 1);//调用IP层函数发送数据
- return(len);
- }
这样要发送的数据填充的sk_buff结构中之后再对UDP数据包添加IP数据报头和MAC帧的首部。最后调用IP层的发送函数发送数据包。
Linux内核--网络栈实现分析(九)--传输层之UDP协议(下)的更多相关文章
- Linux内核--网络栈实现分析(七)--数据包的传递过程(下)
本文分析基于Linux Kernel 1.2.13 原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7545855 更多请查看专栏,地 ...
- Linux内核--网络栈实现分析(二)--数据包的传递过程--转
转载地址http://blog.csdn.net/yming0221/article/details/7492423 作者:闫明 本文分析基于Linux Kernel 1.2.13 注:标题中的”(上 ...
- Linux内核--网络栈实现分析(十一)--驱动程序层(下)
本文分析基于Linux Kernel 1.2.13 原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7555870 更多请查看专栏,地 ...
- Linux内核--网络栈实现分析(五)--传输层之UDP协议(上)
本文分析基于Linux Kernel 1.2.13 原创作品,转载请标明出处http://blog.csdn.net/yming0221/article/details/7532512 更多请看专栏, ...
- Linux内核--网络栈实现分析(一)--网络栈初始化
本文分析基于内核Linux Kernel 1.2.13 原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7488828 更多请看专栏, ...
- Linux内核--网络栈实现分析(一)--网络栈初始化--转
转载地址 http://blog.csdn.net/yming0221/article/details/7488828 作者:闫明 本文分析基于内核Linux Kernel 1.2.13 以后的系列博 ...
- Linux内核--网络栈实现分析(三)--驱动程序层+链路层(上)
本文分析基于Linux Kernel 1.2.13 原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7497260 更多请看专栏,地址 ...
- Linux内核--网络栈实现分析(六)--应用层获取数据包(上)
本文分析基于内核Linux 1.2.13 原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7541907 更多请看专栏,地址http: ...
- Linux内核--网络栈实现分析(四)--网络层之IP协议(上)
本文分析基于Linux Kernel 1.2.13 原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7514017 更多请看专栏,地址 ...
随机推荐
- Velocity语言的介绍
Velocity语言的介绍 2016-09-06 15:39:25 语言介绍 Velocity是一种Java模版引擎技术,是一个基于Java的模板引擎(template engine).她允许任何人简 ...
- iOS9系统分享失败问题解决
因为iOS9系统需要设置打开QQ和微信的白名单,如果出现无法分享或者直接提示分享失败,试一下在infoPlist中添加以下白名单 http://wiki.mob.com/ios9-对sharesdk的 ...
- javascript (js)判断手机号码中国移动、中国联通、中国电信
我国使用的手机号码为11位,其中各段有不同的编码方向:前3位———网络识别号:第4-7位———地区编码:第8-11位———用户号码. 中国移动134.135.136.137.138.139.150.1 ...
- 简易购物车 --day2
代码段 f =float(input('输入你的工资')) goods=['1.apple','2.mac','3.ph','4.python','5.php'] price=[35,26.5,14, ...
- c#获取ip的方法cdn加速获取真实ip方法
服务端://方法一HttpContext.Current.Request.UserHostAddress; //方法二HttpContext.Current.Request.ServerVariabl ...
- Windows系统下部署安装一个/多个Tomcat8
首先从http://tomcat.apache.org/上下载Tomcat8.0压缩版的,解压到指定路径后即可. 第一:在Windows系统中安装部署单个Tomcat 对于这种情况, ...
- javascript父级鼠标移入移出事件中的子集影响父级的处理方法
一.我们先分析其产生的原因: 1.当鼠标从父级移入子集时触发了父级的两个事件:a.父级的mouseout事件(父级离开到子集):b.由于事件冒泡影响,又触发了父级的mouseover事件(父级移入父级 ...
- 也说说angularJs里的evalAsync
虽说angular都快出2.0了,到了2.0这些东东都会被干掉.不过我们眼前的事还是要处理. $evalAsync和$timeout到底什么区别,网上说法很多,最近看到的是说在directive里就怎 ...
- css3之多列
- XAMARIN +VS2015 ANDROID 开发禁止屏幕自动转动 Portrait,Nosensor
网上有很多java的写法,但是放在C#中都无法使用,其实有时候还是安下心来认真的去看官网文档比在百度或者google来的快的多 this.RequestedOrientation = Android. ...