windows7 python 指定源组播 10049_Python3组播通信编程实现教程(发送者+接收者)

一、说明

1.1 标准组播解释

通信分为单播、多播(即组播)、广播三种方式

单播指发送者发送之后,IP数据包被路由器发往目的IP指定的唯一一台设备的通信形式,比如你现在与web服务器通信就是单播形式

广播指发送者发送之后,IP数据包被路由器发给与其连接的所有设备的通信形式

组播指发送者发送之后,IP数据包被路由器发往目的IP对应组播组名下所有主机的通信形式

1.2 个人理解组播解释

对于标准的组播解释,说明似乎还算是清楚的,但具体到技术就有很多问题。比如我将数据包发往一个组播地址,这个组播地址对应一台物理设备吗?如果不是一台物理设备那谁依据什么向哪些主机发送该数据包等等。

结合各资料和自己测试的情况总结出了以下几点:

1) 编写发送程序:组播数据包是且只是目的IP是组播保留地址的UDP数据包,与正常UDP数据包的区别只是其目的IP是组播保留IP

2) 发送数据包主机:网卡在看到目的IP是组播保留IP后,自动将目的mac地址改成组播mac地址然后向其各端口都发送出去

3) 交换机:交换机在接收到数据包之后,通过目的mac地址认识到这是一个组播数据包,修改源mac为自己mac、保持目的mac为组播mac不变向其各端口都发送出去(交换机对组播包的处理和广播包应该是一样的,或者说对于交换机只有单播包和广播包)

4) 路由器:路由器在接收到数据包之后,通过目的mac地址或目的ip地址认识到这是一个组播数据包,修改源mac为自己mac、保持目的mac为组播mac不变,保持源IP不变、保持目的IP为组播保留IP不变,依照与路由表类似的“组播组地址表”向与目的IP匹配的一个或多端口将数据包发送出去

5) 接收数据包主机:接收数据包主机要想接收到发送主机发送的数据包,首先他要(向路由器说明)加入发送者发往的组播组,然后他要在本地启动一个进程监听发送者发往的端口

6) 组播需要硬件支持,有些路由器是不支持组播的,就直观感受看如果在全球实现组播那维护“组播组地址表”会给路由器带来很大负担路由大厂商应该也不是很愿意支持组播;也就是说理论上组播可以在广域网上实现,但其实一般只在局域网中(能够)使用。

7)  注意从本质上而言,接收组播数据包的主机只是启了一个UDP监听,他本身并不能识别是组播发过来的数据包还是直接发过来的数据包(除非对收到的数据包的目的IP是否为组播IP进行判断,但获取目的IP是件很麻烦的事)。也就是说该监听不只是可以接收组播数据包,任何其他如果主机直接向该监听的端口发送UDP数据包该主机也是可以接收到的(已确认过)。

假设使用组播地址为239.255.255.252,使用组播端口为23456,通信举例如下:

发送者S----发送者向239.255.255.252:23456发送一个UDP数据包Packet1

接收者R1(假设其IP地址为134.192.1.100)----第一步启动进程监听239.255.255.252:23456;第二步通过setsockopt加入组播组(239.255.255.252)

接收者R2(假设其IP地址为134.192.1.101)----第一步启动进程监听239.255.255.252:23456;第二步通过setsockopt加入组播组(239.255.255.252)

最终效果----发送者发往239.255.255.252:23456的udp数据包,R1的23456端口收到一份Packet1,R2的23456端口收到一份Packet1

1.3 谁是服务端引发的混乱

我在前面一直使用“发送者”、“接收者”,而没有使用“服务端”、“客户端”,因为“服务端”和“客户端”在组播中容易引发混乱。

在我们一般的socket编程中都是服务端去bind;但在组播中是反过来,客户端(接收者)去bind,而发送者(服务端)是不用去bind的(注意是不用而不是不能,你非要bind也是可以的,bind和不bind只是使用固定端口还是使用随机端口的区别)。

有些小伙伴意识到了这个问题,为了与习惯一致,所以直接将发送者称为客户端,接收者称为服务端。

其实这种叫法是不合适的,以初高中常见的电脑课场景为例:老师控制所有电脑显示老师的电脑操作,这时作为发送者的老师电脑从认知上确实应该是服务端而不是客户端才对。

如果你读了半天没听懂这里在说什么,那不必在意,记得组播中尽里使用“发送者”和“接收者”,少用“服务端”和“客户端”就对了。

1.4 监听组播地址与监听本地地址的区别讨论

在一般的关于组播的文章中,接收者设置的监听地址都是本地地址(如134.192.1.100:23456);但在前面1.2中我们要求接收者R1和R2监听的不是本地地址,而是组播地址239.255.255.252:23456。这是为什么呢?

首先说,这两种监听形式都可以接收到发往239.255.255.252:23456的组播数据包。他们之间的区别是,监听239.255.255.252:23456地址能且只能接收发往239.255.255.252:23456的数据包,而监听134.192.1.100:23456除了能接收发往239.255.255.252:23456的数据包外还能接收直接发往134.192.1.100:23456的数据包。

这样造成的安全区别是,假如接收者实现了这么一项功能:接收到一个打开telnet的命令就直接开启本机的telnet服务。如果监听的是239.255.255.252:23456那么攻击者只有通过局域网内主机发出组播数据包才能打开telnet,但如果监听的是134.192.1.100:23456那么攻击者可以远程直接向134.192.1.100:23456发送数据包开启telnet。

linux上可以通过SO_BINDTODEVICE选项绑定网卡然后设置监听组播地址,但Windows没有实现SO_BINDTODEVICE暂时也不知道如何实现类似功能,所以在下边代码中我也只是linux系统设置了监听组播地址其他系统仍只是监听本地地址。

二、程序实现

2.1 程序代码

发送者代码:

importtimeimportsocket#组播组IP和端口

mcast_group_ip = '239.255.255.252'mcast_group_port= 23456

defsender():#建立发送socket,和正常UDP数据包没区别

send_sock =socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)#每十秒发送一遍消息

whileTrue:

message= "this message send via mcast !"

#发送写法和正常UDP数据包的还是完全没区别

#猜测只可能是网卡自己在识别到目的ip是组播地址后,自动将目的mac地址设为多播mac地址

send_sock.sendto(message.encode(), (mcast_group_ip, mcast_group_port))print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}: message send finish')

time.sleep(10)if __name__ == "__main__":

sender()

接收者代码:

importsysimportstructimporttimeimportsocket#linux能绑定网卡这里绑定组播IP地址不会服错,windows没法绑定网卡这里不能绑定组播IP地址只能绑定本网卡IP地址

if "linux" insys.platform:#绑定到的网卡名,如果自己的不是eth0则注意修改

nic_name = "eth0"

#监听的组播地址

mcast_group_ip = "239.255.255.252"

else:

mcast_group_ip=socket.gethostbyname(socket.gethostname())

mcast_group_port= 23456

defreceiver():#建立接收socket,和正常UDP数据包没区别

sock =socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)#25是linux上的socket.SO_BINDTODEVICE的宏定义,但由于windows没实现SO_BINDTODEVICE,所以python索性也就没有实现SO_BINDTODEVICE,我们直接使用25

#windows没有实现SO_BINDTODEVICE,所以不能通过这种方式绑定网卡,windows怎么实现绑定网卡暂不清楚

if "linux" insys.platform:

sock.setsockopt(socket.SOL_SOCKET,25, nic_name)#linux能绑定网卡这里绑定组播IP地址不会服错,windows没法绑定网卡这里不能绑定组播IP地址只能绑定本网卡IP地址

sock.bind((mcast_group_ip, mcast_group_port))#加入组播组

mreq = struct.pack("=4sl", socket.inet_aton(mcast_group_ip), socket.INADDR_ANY)

sock.setsockopt(socket.IPPROTO_IP,socket.IP_ADD_MEMBERSHIP,mreq)#允许端口复用,看到很多教程都有没想清楚意义是什么,我这里直接注释掉

#sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

#设置非阻塞,看到很多教程都有也没想清楚有什么用,我这里直接注释掉

#sock.setblocking(0)

whileTrue:try:

message, addr= sock.recvfrom(1024)print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}: Receive data from {addr}: {message.decode()}')except:print("while receive message error occur")if __name__ == "__main__":

receiver()

2.2 运行截图

发送者截图:

接收者运行截图:

参考:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/500962.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

servlet如何使用session把用户的手机号修改_SpringBoot源码学习系列之嵌入式Servlet容器...

1、前言简单介绍SpringBoot的自动配置就是SpringBoot的精髓所在;对于SpringBoot项目是不需要配置Tomcat、jetty等等Servlet容器,直接启动application类既可,SpringBoot为什么能做到这么简捷?原因就是使用了内嵌的Servlet容器&…

mybatisplus新增返回主键_第17期:索引设计(主键设计)

表的主键指的针对一张表中的一列或者多列,其结果必须能标识表中每行记录的唯一性。InnoDB 表是索引组织表,主键既是数据也是索引。主键的设计原则1. 对空间占用要小上一篇我们介绍过 InnoDB 主键的存储方式,主键占用空间越小,每个…

mysql 集群与主从_Mysql集群和主从

1、Mysql cluster: share-nothing,分布式节点架构的存储方案,以便于提供容错性和高性能。需要用到mysql cluster安装包,在集群中的每一个机器上安装。有三个关键概念:Sql节点(多个),数据节点(多个),管理节点(一个)&…

python四则运算_四则运算 python

java转换json需要导入的jar包,org/apache/commons/lang/exception/NestableRuntimeException缺少相应jar包都会有异常,根据异常找jar包导入...... 这里我说下lang包,因为这个包我找了好半天: 我用的是: commons-lang…

mysql 字段排重_MySQL 根据单个、多个字段排重

情景是这样的 首先我们业务需要 在一张流水表中需要进行流水的记录 这个记录是从别的平台拉过来的数据 但是他们数据无唯一约束 即流水这样就很有可能出现单条数据重复的问题所以这种情况 用join的话 效率可能不是很大 所以就写了以下sql注意 排重后还需保留一个唯一有效的记录…

python开发框架 代码生成_我的第一个python web开发框架(31)——定制ORM(七)...

几个复杂的ORM方式都已介绍完了,剩下一些常用的删除、获取记录数量、统计合计数、获取最大值、获取最小值等方法我就不一一详细介绍了,直接给出代码大家自行查看。1 #!/usr/bin/env python2 #codingutf-834 from common importdb_helper567 classLogicBa…

mysql里边字符函数_mysql函数(一.字符函数)

一.字符函数1.LENGTH(str)字符长度函数:一个汉字为三个字符(1)查看某字符串的长度(比如名字)select LENGTH(sunchuangye); 结果:11(2)根据字符长度进行倒序(比如名字)select id,userName FROM t_user ORDER BY LENGTH(userName) DESC;2.CONCAT(str1,s…

redis缓存原理与实现_基于Redis实现范围查询的IP库缓存设计方案

点击上方“码农沉思录” 发现更多精彩我先说下结果。我现在还不敢放线上去测,这是本地测的数据,我4g内存的电脑本地开redis,一次都没写完过全部数据,都是写一半后不是redis挂就是测试程序挂。可以肯定的是总记录数是以千万为单位…

linux mysql提示1045_linux mysql ERROR 1045

介绍了一下安装MySQL后登陆MySQL时会遇到ERROR 1045 (28000): Access denied for user rootlocalhost (using password: NO) 这个错误,当时不知道真正的原因,搜索了一些网上的资料,测试验证了如何解决这个问题,但是一直不知道具体…

mysql原生库_Mysql数据库的一些简单原生sql语句

原生sql语句查询:select * from 表名 :查找表内所有数据, * 代表所有where 具体条件 :where作位查询sql语句条件,例 select * from 表名 where 字段名指定值order by 升降序:与desc和asc使用,通常以int类型字段进行升…

有向图生成树是如何画的_漫画:什么是最小生成树?

作者 | 小灰来源 | 程序员小灰————— 第二天 —————————————————首先看看第一个例子,有下面这样一个带权图:它的最小生成树是什么样子呢?下图绿色加粗的边可以把所有顶点连接起来,又保证了边的权值之和最小&a…

python经济_python生成器——懒到欠揍,但很经济

生成器的特点是工作到一半,就会停下来看别人干活直至有人踢它屁股,这时它才继续往下干活。实现这一功能的精髓要用到yield。生成器是一种特殊的迭代器,因此我们先来了解一下什么是迭代器。我们都知道著名的斐波那契数列:1、1、2、…

ue默认高亮mysql_UE设置打开文件的默认高亮语言

最近使用UE时,需要频繁地打开.ec文件,.ec文件参照的是C/C的语法,每次打开时,都需要在工具栏上点击“查看方式->C/C”。觉得很繁琐,于是想查找一下设置,让UE打开.ec文件时,默认使用的C/C语法高…

printf 指针地址_c语言对指针的理解

先来讲一下本人学指针的经历:大一的时候刚接触c语言对指针这东西真的是太迷了,感觉麻烦难懂不想其他语言一样。但是搞懂以后就被指针的魅力吸引甚至喜欢上c语言。不多讲,开始!(文章可能有些长,但放心全是基础的东西&am…

mysql 命令 _Mysql常用命令行大全

7.1 一个建库和建表的实例1drop database if exists school; //如果存在SCHOOL则删除create database school; //建立库SCHOOLuse school; //打开库SCHOOLcreate table teacher //建立表TEACHER(id int(3) auto_increment not null primary key,name char(10) not null,address…

python进程监控 supervisor_使用Python的Supervisor进行进程监控以及自动启动

做服务器端开发的同学应该都对进程监控不会陌生,最近恰好要更换 uwsgi 为 gunicorn,而gunicorn又恰好有这么一章讲进程监控,所以多研究了下。结合之前在腾讯工作的经验,也会讲讲腾讯的服务器监控是怎么做的。同时也会讲下小团队又…

python 时分秒毫秒_python将时分秒转换成秒的实例

处理数据的时候遇到一个问题,从数据库里导出的数据是时分秒的格式:hh:mm:ss ,现在我需要把它转换成秒,方便计算。原数据可能分两种情况,字段有可能是文本字符串类型的,也有可能是时间类型,他们的…

信息系统项目管理师论文优秀范文_软考 信息系统项目管理师备考指南

1.考试简介信息系统项目管理师考试作为全国计算机技术与软件专业技术资格(水平)考试(一般简称为“软考”)的一个高级级别,是从2005年开始的,一共考了2次,即2005年5月,200…

单片机led闪烁代码_单片机驱动LED发光二极管的电路以及编程

一、单片机驱动单个发光二极管1.电路代码:1.点亮单个LED二极管#include《reg51.h> sbit LED1P1^0&#xff1b;void main(void){LED11&#xff1b;while(1)&#xff1b;{LED10} }2.单个LED数码管以固定频率闪烁#include<reg51.h> sbit LED1P1^0;void Delay(unsigned in…

mysql人事管理系统源代码_人事管理系统(源代码.doc

人事管理系统(源代码附录&#xff1a;毕业设计程序清单设计题目 人事管理系统教 学 班&#xff1a;学生姓名&#xff1a;学 号&#xff1a;指导教师&#xff1a;完成日期&#xff1a;Option ExplicitDim Bupdata As BooleanDim i As IntegerPrivate Sub Cmbdegree_Click()If Cm…