近期由于需要编写能够使同一局域网中的Android客户端与PC端进行自动匹配通信功能的程序,学习并试验了JAVA组播与广播的内容,记录一些理解如下:
一.组播(多播)
背景知识:组播使用UDP对一定范围内的地址发送相同的一组Packet,即一次可以向多个接受者发出信息,其与单播的主要区别是地址的形式。IP协议分配了一定范围的地址空间给多播(多播只能使用这个范围内的IP),IPv4中组播地址范围为224.0.0.0到239.255.255.255。
JAVA编程:java中通过MulticastSocket实例进行通信,使用时涉及到几个概念①TTL(Time To Live),每个IP报文都包含一个TTL(是一个数字),报文每被一个路由转发一次它的TTL减1,当TTL变为0时,该报文被丢弃②多播组(multicast group),接受者只有加入这个组才能获取发送到该组的报文(这就确定了组播的对象)
JAVA代码:
发送端(Android手机):
//-----------------------------------------------------------------------------------------
MulticastSocket mSocket = new MulticastSocket( 30001); //生成套接字并绑定30001端口
InetAddress group = InetAddress . getByName( "239.0.0.1"); //设定多播IP
byte [] buff = "QQ" . getBytes( "utf-8"); //设定多播报文的数据
mSocket . joinGroup( group); //加入多播组,发送方和接受方处于同一组时,接收方可抓取多播报文信息
mSocket . setTimeToLive( 4); //设定TTL
//设定UDP报文(内容,内容长度,多播组,端口)
DatagramPacket packet = new DatagramPacket( buff , buff . length , group , 30001);
mSocket . send( packet); //发送报文
mSocket . close(); //关闭套接字
//-----------------------------------------------------------------------------------------
接收端(PC):
//-----------------------------------------------------------------------------------------
MulticastSocket s = new
MulticastSocket(
30001);
//生成套接字并绑定端口
InetAddress group = InetAddress . getByName( "239.0.0.1"); //设定多播IP
s . joinGroup( group); //接受者加入多播组,需要和发送者在同一组
DatagramPacket packet = new DatagramPacket( buffer , 100); //创建接收报文,以接收通过多播传递过来的报文
s . receive( packet); //接收多播报文,程序停滞等待直到接收到报文
s . close(); //关闭套接字
//-----------------------------------------------------------------------------------------
注意事项:
1.windows系统中的TCP/IP 的媒体感知功能会导致组播报出这样的错误:
java.net.SocketException: IP_ADD_MEMBERSHIP failed (out of hardware filters?)
windows7环境下解决方法如下:
使用注册表编辑器 (运行中键入regedit) 来查看下面的注册表项: HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Tcpip\Parameters (Tcpip类似文件夹一样的图标能展开里面有Parameters,第一次找了很久)
添加以下注册表值:
数值名称:DisableDHCPMediaSense 数据类型:REG_DWORD 即(DWORD(32-位)值)创建后右击修改其值为1,即关闭,重启机器即可
2.笔者用PC直接连接宽带打开程序报错,切断宽带运行正常,猜测为路由器拒绝转发组播,此问题有待研究(由于笔者使用Windows hostednetwork创建笔记本自己的网络,将手机加入进来进行测试,所以对程序的测试仍可进行),此为实际程序中放弃使用组播的一个原因
3.不是所有的路由器都支持组播功能,并且一些支持组播的路由器默认为关闭组播的状态,所以目前使用组播写程序时需要考虑实际可用性的问题
二.广播
背景知识:
使用广播,本地网络中所有的主机都会受到一份数据副本。广播使用UDP报文,IPv4使用(255.255.255.255)地址发送广播,本地广播绝不会被路由器转发,即广播信息会被限制在本地网络之内。
JAVA编程:
UDP单播和广播类似,主要是IP不同,都是用DatagramSocket对象进行发送
JAVA代码:
发送端(Android手机)
//-----------------------------------------------------------------------------------------
byte [] buff = "QQ" . getBytes( "utf-8"); //设定报文信息
DatagramSocket socket = new DatagramSocket(); //建立套接字,参数端口号不填写,系统会自动分配一个可用端口
//创建报文,包括报文内容,内容长度,报文地址(这里全1地址即为广播),端口号(接受者需要使用该端口)
DatagramPacket packet = new DatagramPacket( buff , buff . length , InetAddress . getByName( "255.255.255.255" ), 30000);
socket . send( packet); //发送报文
socket . disconnect(); //断开套接字
socket . close(); //关闭套接字
//-----------------------------------------------------------------------------------------
接受端(PC):
//-----------------------------------------------------------------------------------------
DatagramSocket socket = new DatagramSocket( 30000); //创建套接字
byte [] buffer; //创建接收字符串
buffer = new byte [ 35 ];
DatagramPacket packet = new DatagramPacket( buffer , buffer . length); //创建接收报文,以接收通过广播传递过来的
System . out . println( "Listening at UDP(30000)....");
socket . receive( packet); //接收报文,程序停滞等待直到接收到报文
socket . disconnect(); //断开套接字
socket . close(); //关闭套接字
//-----------------------------------------------------------------------------------------
一.组播(多播)
背景知识:组播使用UDP对一定范围内的地址发送相同的一组Packet,即一次可以向多个接受者发出信息,其与单播的主要区别是地址的形式。IP协议分配了一定范围的地址空间给多播(多播只能使用这个范围内的IP),IPv4中组播地址范围为224.0.0.0到239.255.255.255。
JAVA编程:java中通过MulticastSocket实例进行通信,使用时涉及到几个概念①TTL(Time To Live),每个IP报文都包含一个TTL(是一个数字),报文每被一个路由转发一次它的TTL减1,当TTL变为0时,该报文被丢弃②多播组(multicast group),接受者只有加入这个组才能获取发送到该组的报文(这就确定了组播的对象)
JAVA代码:
发送端(Android手机):
//-----------------------------------------------------------------------------------------
MulticastSocket mSocket = new MulticastSocket( 30001); //生成套接字并绑定30001端口
InetAddress group = InetAddress . getByName( "239.0.0.1"); //设定多播IP
byte [] buff = "QQ" . getBytes( "utf-8"); //设定多播报文的数据
mSocket . joinGroup( group); //加入多播组,发送方和接受方处于同一组时,接收方可抓取多播报文信息
mSocket . setTimeToLive( 4); //设定TTL
//设定UDP报文(内容,内容长度,多播组,端口)
DatagramPacket packet = new DatagramPacket( buff , buff . length , group , 30001);
mSocket . send( packet); //发送报文
mSocket . close(); //关闭套接字
//-----------------------------------------------------------------------------------------
接收端(PC):
//-----------------------------------------------------------------------------------------
MulticastSocket s = new
InetAddress group = InetAddress . getByName( "239.0.0.1"); //设定多播IP
s . joinGroup( group); //接受者加入多播组,需要和发送者在同一组
DatagramPacket packet = new DatagramPacket( buffer , 100); //创建接收报文,以接收通过多播传递过来的报文
s . receive( packet); //接收多播报文,程序停滞等待直到接收到报文
s . close(); //关闭套接字
//-----------------------------------------------------------------------------------------
注意事项:
java.net.SocketException: IP_ADD_MEMBERSHIP failed (out of hardware filters?)
二.广播
背景知识:
使用广播,本地网络中所有的主机都会受到一份数据副本。广播使用UDP报文,IPv4使用(255.255.255.255)地址发送广播,本地广播绝不会被路由器转发,即广播信息会被限制在本地网络之内。
JAVA编程:
UDP单播和广播类似,主要是IP不同,都是用DatagramSocket对象进行发送
JAVA代码:
发送端(Android手机)
//-----------------------------------------------------------------------------------------
byte [] buff = "QQ" . getBytes( "utf-8"); //设定报文信息
DatagramSocket socket = new DatagramSocket(); //建立套接字,参数端口号不填写,系统会自动分配一个可用端口
//创建报文,包括报文内容,内容长度,报文地址(这里全1地址即为广播),端口号(接受者需要使用该端口)
DatagramPacket packet = new DatagramPacket( buff , buff . length , InetAddress . getByName( "255.255.255.255" ), 30000);
socket . send( packet); //发送报文
socket . disconnect(); //断开套接字
socket . close(); //关闭套接字
//-----------------------------------------------------------------------------------------
接受端(PC):
//-----------------------------------------------------------------------------------------
DatagramSocket socket = new DatagramSocket( 30000); //创建套接字
byte [] buffer; //创建接收字符串
buffer = new byte [ 35 ];
DatagramPacket packet = new DatagramPacket( buffer , buffer . length); //创建接收报文,以接收通过广播传递过来的
System . out . println( "Listening at UDP(30000)....");
socket . receive( packet); //接收报文,程序停滞等待直到接收到报文
socket . disconnect(); //断开套接字
socket . close(); //关闭套接字
//-----------------------------------------------------------------------------------------