`
thecloud
  • 浏览: 879861 次
文章分类
社区版块
存档分类
最新评论

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层的发送函数发送数据包。


分享到:
评论

相关推荐

    多图表实现员工满意度调查数据分析python

    员工满意度是指员工对于工作环境、待遇、职业发展和组织管理等方面的满意程度。它是衡量员工对工作的整体感受和情绪状态的重要指标。

    2020届软件工程本科毕业生毕业设计项目.zip

    2020届软件工程本科毕业生毕业设计项目

    基于stm32平衡小车

    平衡小车 基于stm32 平衡小车 基于stm32 平衡小车 基于stm32

    c语言火车票订票管理源码.rar

    c语言火车票订票管理源码.rar

    施耐德PLC例程源码四台水泵的轮换

    施耐德PLC例程源码四台水泵的轮换提取方式是百度网盘分享地址

    node-v16.13.2-linux-s390x.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    digix算法创新大赛2019baseline.zip

    digix算法创新大赛2019baseline

    三菱PLC小型立体仓库项目.zip

    三菱PLC小型立体仓库项目.zip 叉手篮具到位检测 入库2电机前限

    node-v15.3.0-linux-s390x.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    软考高项-ITTO背诵打印必过版-2024-高项已通过

    软考高项_ITTO背诵打印必过版_2024_高项已通过

    巧解HTTP三次握手四次挥手流程(超详细).docx

    TCP三次握手及四次挥手详细图解 相对于SOCKET开发者,TCP创建过程和链接折除过程是由TCP/IP协议栈自动创建的.因此开发者并不需要控制这个过程.但是对于理解TCP底层运作机制,相当有帮助. TCP三次握手 所谓三次握手(Three-way Handshake),是指建立一个TCP连接时,需要客户端和服务器总共发送3个包。 三次握手的目的是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号和确认号并交换 TCP 窗口大小信息.在socket编程中,客户端执行connect()时。将触发三次握手。 1.TCP建立流程 第一次握手:建立连接时,客户端发送SYN(Seq = J)包到服务器,并进入到syn_sent状态。等待服务器确认。 第二次握手:服务器收到SYN包,知道了Client端想建立连接. 它会向客户端发送SYN+ ACK包(ack =J+1 TCP 四次挥手 TCP的连接的拆除需要发送四个包,因此称为四次挥手(four-way handshake)。客户端或服务器均可主动发起挥手动作,在socket编程中,任何一方执行close()操作即可产生挥手操作

    node-v13.5.0-linux-arm64.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    欧母龙PLC例程源码扎钢机程序

    欧母龙PLC例程源码扎钢机程序提取方式是百度网盘分享地址

    基于RGB相机的驾驶员注视区域估计_刘觅涵.pdf

    驾驶员注意力检测,驾驶员分神驾驶检测,DMS,汽车智能驾驶,智能座舱

    Unity实现二维码扫描,二维码生成

    Unity实现二维码扫描,二维码生成 提供ZXing.unity.dll可以进行二维码的生成和扫描,扫描的方式是在场景中发射射线,射线获取rawimage的texture并读取,然后作为二维码进行解析。 提供源代码。

    中山大学-计科-操作系统实验.zip

    中山大学-计科-操作系统实验.zip

    施耐德PLC例程源码恒压供水程序(用施耐德TWIDOPLC编的)

    施耐德PLC例程源码恒压供水程序(用施耐德TWIDO PLC编的)提取方式是百度网盘分享地址

    node-v14.8.0-darwin-x64.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    node-v14.6.0-darwin-x64.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    python实现小说词频统计

    小说词频统计是指对一本小说中出现的各个词语进行计数和分析,以确定每个词语在整篇小说中的出现频率。 以下是对小说词频统计的一些基本说明: 数据收集:首先需要获取目标小说的文本数据。这可以通过手动输入、复制粘贴文本内容或使用自动化工具来提取文本。 文本处理:在进行词频统计之前,通常需要对文本数据进行预处理。这可能包括去除标点符号、停用词(如“的”、“是”等)和特殊字符,将文本转换为统一的格式。 词语计数:进行词频统计时,遍历整个文本,逐个词语地计数它们的出现次数。通常会使用字典、哈希表或其他数据结构来存储词语及其计数。

Global site tag (gtag.js) - Google Analytics