当前位置: 首页 > news >正文

BSD协议栈:多播

分用多播和广播数据报

与单播相比,多播与广播需要提交数据报给所有匹配的socket,其他的操作其实大同小异,读者可以参考下文的单播。但是,其中的难点就在于数据报的提交与回收。

实现逻辑:迭代遍历pcb,如果pcb不匹配,就使用continue关键字开启下一轮迭代,直到找到匹配的pcb或迭代到NULL。

如果pcb匹配,判断上一次是否匹配到pcb,如果是,那么调用sbappendaddr提交数据报到上一次的接收队列,并唤醒因为接收队列而阻塞的进程,之后使用last缓存指针保存pcb。

如果last指针为NULL,说明这是第一次匹配到pcb,那就用last保存该pcb,并进行一次是否结束迭代的判断。

但是在提交之前,我们需要拷贝一个副本,

sbappendaddr函数执行成功后会返回1,也就是说,提交数据报成功后就会唤醒阻塞进程。如果返回的是0,说明提交失败,这是因为缓冲区已满导致的问题,所以需要释放mbuf链。除此之外,该函数还会释放mbuf链,但是考虑到我们是多播或广播,可能不是最后一次提交,所以我们需要使用m_copy备份,并使用变量n保存地址,然后提交给接收队列。

这部分程序的精髓在于提交“上一次”,而非“这一次”。如果检查到匹配的pcb就提交数据报,那么我们不得不考虑最后一次可能出现的问题:我们会多留下一个数据报。但是使用“上一次”,当程序运行到这里时,表示前面的循环结束,可以判断是最后一次,因此无需备份,直接使用原始数据报即可。

(这段程序综合考虑了内存的回收释放,对不同情况处理得非常好)

	if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) ||
	    in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) {
		struct socket *last;
		/*
		 * Deliver a multicast or broadcast datagram to *all* sockets
		 * for which the local and remote addresses and ports match
		 * those of the incoming datagram.  This allows more than
		 * one process to receive multi/broadcasts on the same port.
		 * (This really ought to be done for unicast datagrams as
		 * well, but that would cause problems with existing
		 * applications that open both address-specific sockets and
		 * a wildcard socket listening to the same port -- they would
		 * end up receiving duplicates of every unicast datagram.
		 * Those applications open the multiple sockets to overcome an
		 * inadequacy of the UDP socket interface, but for backwards
		 * compatibility we avoid the problem here rather than
		 * fixing the interface.  Maybe 4.5BSD will remedy this?)
		 */

		/*
		 * Construct sockaddr format source address.
		 */
		udp_in.sin_port = uh->uh_sport;
		udp_in.sin_addr = ip->ip_src;
		m->m_len -= sizeof (struct udpiphdr);
		m->m_data += sizeof (struct udpiphdr);
		/*
		 * Locate pcb(s) for datagram.
		 * (Algorithm copied from raw_intr().)
		 */
		last = NULL;
		for (inp = udb.inp_next; inp != &udb; inp = inp->inp_next) {
			if (inp->inp_lport != uh->uh_dport)
				continue;
			if (inp->inp_laddr.s_addr != INADDR_ANY) {
				if (inp->inp_laddr.s_addr !=
				    ip->ip_dst.s_addr)
					continue;
			}
			if (inp->inp_faddr.s_addr != INADDR_ANY) {
				if (inp->inp_faddr.s_addr !=
				    ip->ip_src.s_addr ||
				    inp->inp_fport != uh->uh_sport)
					continue;
			}

			if (last != NULL) {
				struct mbuf *n;

				if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
					if (sbappendaddr(&last->so_rcv,
						(struct sockaddr *)&udp_in,
						n, (struct mbuf *)0) == 0) {
						m_freem(n);
						udpstat.udps_fullsock++;
					} else
						sorwakeup(last);
				}
			}
			last = inp->inp_socket;
			/*
			 * Don't look for additional matches if this one does
			 * not have either the SO_REUSEPORT or SO_REUSEADDR
			 * socket options set.  This heuristic avoids searching
			 * through all pcbs in the common case of a non-shared
			 * port.  It * assumes that an application will never
			 * clear these options after setting them.
			 */
			if ((last->so_options&(SO_REUSEPORT|SO_REUSEADDR) == 0))
				break;
		}

		if (last == NULL) {
			/*
			 * No matching pcb found; discard datagram.
			 * (No need to send an ICMP Port Unreachable
			 * for a broadcast or multicast datgram.)
			 */
			udpstat.udps_noportbcast++;
			goto bad;
		}
		if (sbappendaddr(&last->so_rcv, (struct sockaddr *)&udp_in,
		     m, (struct mbuf *)0) == 0) {
			udpstat.udps_fullsock++;
			goto bad;
		}
		sorwakeup(last);
		return;
	}

相关文章:

  • Visual Basic语言的数据类型
  • Logo语言的图形用户界面
  • jar命令解压jar包及更新jar的配置文件
  • RTMP(Real-Time Messaging Protocol)
  • 网工项目理论1.11 网络出口设计
  • seata基本使用
  • 【Java】Mongodb
  • UI自动化教程 —— 元素定位技巧:精确找到你需要的页面元素
  • Kafka偏移量管理全攻略:从基础概念到高级操作实战
  • 如何在yolov8系列运行自己的数据集
  • NAT(网络地址转换)技术详解:网络安全渗透测试中的关键应用与防御策略
  • 嵌入式人工智能应用-第四章 决策树 6
  • PostgreSQL 创建数据库
  • 一个基于Spring Boot和Vue.js的web商城系统-邻家小铺
  • SyntaxError: invalid syntax
  • MYSQL中的性能调优方法
  • Mac 安装Ollama和llama3,本地部署LobeChat和刘皇叔聊三国
  • Rust编程语言入门教程(四)猜数游戏:一次猜测
  • HarmonyOS4-工具安装
  • 【JavaScript】《JavaScript高级程序设计 (第4版) 》笔记-Chapter15-DOM 扩展
  • 焦点访谈丨售假手段又翻新,警惕化肥“忽悠团”的坑农套路
  • 凤阳文旅局回应鼓楼瓦片脱落:鼓楼楼宇系仿古建筑,动工时已履行报批手续
  • 【社论】鸿蒙破壁,向最难处攻坚
  • “高原笑匠”、西藏著名表演艺术家扎西顿珠去世
  • 人民日报评论员观察:稳企业,全力以赴纾困解难
  • 甘肃省白银市一煤矿发生透水事故,3人失联