组播概念
多播(Multicast):也称为多播,在一台源主机和一组目的主机之间建立单点对多点的网络连接。如果一台源主机同时给多个目的主机传输相同的数据,也只需发送一份相同数据包,提高了数据传送效率,减少了骨干网络出现拥塞的可能性,较好地解决了单点发送多点接收的问题。
多播的工作原理:
1.多播源将数据报发送到特定的多播组,只有属于多播组的成员才能接收到数据报。
2.多播组成员不局限于同一个网络,因特网上的主机可以通过网际组管理协议加入某个多播组中,也可以动态离开该组。
3.相关路由器将跟踪这种关系并形成一条到达多播组中每个成员的无回路路径。
4.一旦多播数据报传递到某多播路由器,它将根据多播组的组成信息将该数据报转发到每一个多播成员。
址分配与MAC地址映射:
1.TCP/IP中引入多播地址,每个多播组都需要一个多播地址来标识。
2.IP数据报封装在数据链路层中,每个多播组还需要一个多播MAC地址。
3.为了使每个主机既能接收单播数据又能接收多播数据,每一个多播组中的主机都有多个IP和MAC地址。
IPv6都为多播专门划分出一个地址范围
,即IPv6中的多播地址
配与MAC地址映射:
目前大部分物理网络都支持硬件多播,如以太网。数据报到达相应的物理网络之后,就要利用硬件多播机制进行数据报传送,最终交付给相应的主机成员。
简单代码示例:
BroadCast.java:
package Pack;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import javax.swing.JTextArea;
public class BroadCast extends Thread{
public int port=0; //组播端口
String Ip=""; //组播ip
JTextArea recTextArea;
String MyMessage="";
String name=""; //昵称
MulticastSocket multicastSocket=null;
public BroadCast(int port,String Ip,String name,JTextArea recTextArea)//构造函数
{
this.port=port;
this.Ip=Ip;
this.name=name;
this.recTextArea=recTextArea;
}
public void sendMessage(String message)//组播成员发送信息
{
try{
String string=this.name;
string+=":"+message;
message=string+"\n";
byte[] buf=message.getBytes();
DatagramPacket datagramPacket=new DatagramPacket(buf, buf.length);
InetAddress address=InetAddress.getByName(Ip);
datagramPacket.setAddress(address);
datagramPacket.setPort(port);
multicastSocket.send(datagramPacket);
}
catch(IOException e)
{
e.printStackTrace();
}
}
public void StopChat()
{
sendMessage("组播用户下线"); //提示 组播用户下线
}
public void ClearScreen()
{
recTextArea.setText(""); //清空 “接收发信息”框
}
public void run() {//启动线程
try{
multicastSocket=new MulticastSocket(this.port);
InetAddress address=InetAddress.getByName(Ip);
multicastSocket.joinGroup(address);
sendMessage("组播用户上线"); //提示 组播用户上线
while(true){
byte[] buf=new byte[1024];
DatagramPacket datagramPacket=new DatagramPacket(buf, buf.length);
multicastSocket.receive(datagramPacket);
String string=new String(datagramPacket.getData(),0,datagramPacket.getLength());
this.recTextArea.append(string);
}
}catch(IOException e)
{
e.printStackTrace();
}
multicastSocket.close();
}
}
Test.java
package Pack;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class Test{
private JTextField portTxtFiled=new JTextField();
private JTextField CastIPTxtFiled=new JTextField();
private JTextField nameField=new JTextField();
private JButton startChatBtn=new JButton("开始聊天");
private JButton stopChatBtn=new JButton("断开");
private JTextArea receiveMesArea=new JTextArea();
JScrollPane jScrollPane=new JScrollPane(receiveMesArea);
private JTextArea sendMesArea=new JTextArea();
private JButton clearScrBtn=new JButton("清屏");
private JButton sendBtn=new JButton("发送");
private JButton quitBtn=new JButton("退出");
private BroadCast broadCast=null;
@SuppressWarnings("deprecation")
public void InitFrame()
{
JFrame mainFrame=new JFrame();
mainFrame.setLayout(null);
mainFrame.setSize(600, 600);
mainFrame.setLayout(null);
JLabel JLabel32= new JLabel("组播昵称");
JLabel32.setBounds(20, 20, 60, 20);
mainFrame.add(JLabel32);
nameField.setBounds(80, 20, 100, 20);
mainFrame.add(nameField);
JLabel JLabel2= new JLabel("端口号");
JLabel2.setBounds(320, 20, 40, 20);
mainFrame.add(JLabel2);
portTxtFiled.setBounds(360, 20, 100, 20);
mainFrame.add(portTxtFiled);
JLabel JLabel3= new JLabel("组播地址");
JLabel3.setBounds(20, 80, 60, 20);
mainFrame.add(JLabel3);
CastIPTxtFiled.setBounds(80, 80, 100, 20);
mainFrame.add(CastIPTxtFiled);
startChatBtn.setBounds(220, 80, 100, 20);
stopChatBtn.setBounds(360, 80, 100, 20);
mainFrame.add(startChatBtn);
mainFrame.add(stopChatBtn);
JLabel JLabel4= new JLabel("接收发消息");
JLabel4.setBounds(20, 140, 100, 20);
jScrollPane.setBounds(20,160,460,130);
jScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
mainFrame.add(jScrollPane);
mainFrame.add(JLabel4);
JLabel JLabel5= new JLabel("发送消息");
JLabel5.setBounds(20, 300, 100, 20);
sendMesArea.setBounds(20, 320, 460, 100);
mainFrame.add(sendMesArea);
mainFrame.add(JLabel5);
clearScrBtn.setBounds(230, 460, 100, 20);//清屏
mainFrame.add(clearScrBtn);
sendBtn.setBounds(380, 460, 100, 20); //发送
mainFrame.add(sendBtn);
quitBtn.setBounds(80, 460, 100, 20); //退出
mainFrame.add(quitBtn);
mainFrame.show();
startChatBtn.setEnabled(true);
stopChatBtn.setEnabled(false);
sendBtn.setEnabled(false);
startChatBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
StartChat();
}
});
sendBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
SendMessage();
}
});
clearScrBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ClearScreen();
}
});
stopChatBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
startChatBtn.setEnabled(true);
stopChatBtn.setEnabled(false);
sendBtn.setEnabled(false);
StopChat();
}
});
quitBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
StopChat();
System.exit(0);
}
});
}
public static void main(String[] args)
{
Test client=new Test();
client.InitFrame();
}
public void StartChat()
{
String port= portTxtFiled.getText();
String castIp=portTxtFiled.getText();
if(!castIp.equals("") && !port.equals(""))
{
startChatBtn.setEnabled(false);
stopChatBtn.setEnabled(true);
sendBtn.setEnabled(true);
broadCast=new BroadCast(Integer.parseInt(portTxtFiled.getText()),CastIPTxtFiled.getText(),nameField.getText(), receiveMesArea);
broadCast.start();
}
}
public void SendMessage()
{
broadCast.sendMessage(sendMesArea.getText());
}
public void ClearScreen()
{
broadCast.ClearScreen();
}
@SuppressWarnings("deprecation")
public void StopChat()
{
broadCast.StopChat();
broadCast.stop();
}
}
演示说明:该程序可同时打开多个,以模拟多个组播成员,注意多播地址是否正确。