在实现这个问题:主机不断地重复播出节目预报,可以保证加入到同一组的主机随时可接收到广播信息。接收者将正在接收的信息放在一个文本域中,并将接收的全部信息放在另一个文本域中。
接收程序出错:Exception in thread "AWT-EventQueue-0" java.lang.IllegalThreadStateException
at java.lang.Thread.start(Unknown Source)
at Receive.actionPerformed(Receive.java:68)
at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
at java.awt.Component.processMouseEvent(Unknown Source)
at javax.swing.JComponent.processMouseEvent(Unknown Source)
at java.awt.Component.processEvent(Unknown Source)
at java.awt.Container.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Window.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
Exception in thread "AWT-EventQueue-0" java.lang.IllegalThreadStateException
at java.lang.Thread.start(Unknown Source)
at Receive.actionPerformed(Receive.java:68)
at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
at java.awt.Component.processMouseEvent(Unknown Source)
at javax.swing.JComponent.processMouseEvent(Unknown Source)
at java.awt.Component.processEvent(Unknown Source)
at java.awt.Container.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Window.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
其中广播主机程序代码为:
import java.io.IOException; //导入java.io.IOException类
import java.net.*; //导入java.net包
public class Weather extends Thread{ //创建类。该类为多线程执行程序
String weather = "节目预报:八点有大型晚会,请收听";
int port = 9898; //定义端口
InetAddress iaddress = null; //创建InetAddress对象
MulticastSocket socket = null; //声明多点广播套接字
Weather(){ //构造方法
try {
iaddress = InetAddress.getByName("224.255.10.0"); //实例化InetAddress,指定地址
socket = new MulticastSocket(port); //实例化多点广播套接字
socket.setTimeToLive(1); //指定发送范围是本地网络
socket.joinGroup(iaddress); //加入广播组
} catch (Exception e) {
e.printStackTrace(); //输出异常信息
}
}
public void run(){ //run()方法
while(true){
DatagramPacket packet = null; //声明DatagramPacket对象
byte data[] = weather.getBytes(); //声明字节数组
packet = new DatagramPacket(data,data.length,iaddress,port); //将数据打包
System.out.println(new String(data)); //将广播信息输出
try {
socket.send(packet); //发送数据
sleep(3000); //线程休眠
} catch (Exception e) {
e.printStackTrace(); //输出异常信息
}
}
}
public static void main(String[] args) { // 主方法
Weather w = new Weather(); //创建本类对象
w.start(); //启动线程
}
}
接收代码为:
import java.awt.event.*;              //导入java.awt.event包
import javax.swing.*;
import java.awt.*;
import java.net.*;
public class Receive extends JFrame implements Runnable, ActionListener {
int port;                 //定义int型变量
InetAddress group = null;             //声明InetAddress对象
MulticastSocket socket = null;             //创建多点广播套接字对象
JButton ince = new JButton("开始接收");             //创建按钮对象
JButton stop = new JButton("停止接收");
JTextArea inceAr = new JTextArea(10, 10);             //显示接收广播的文本域
JTextArea inced = new JTextArea(10, 10);
Thread thread;                 //创建Thread对象
boolean b = false;                 //创建boolean型变量
public Receive() {                 //构造方法
super("广播数据报");             //调用父类方法
thread = new Thread(this);
ince.addActionListener(this);             //绑定按钮ince的单击事件
stop.addActionListener(this);             //绑定按钮stop的单击事件
inceAr.setForeground(Color.blue);             //指定文本域中文字颜色
JPanel north = new JPanel();             //创建Jpane对象
north.add(ince);                 //将按钮添加到面板north上
north.add(stop);
add(north, BorderLayout.NORTH);                 //将north放置在窗体的上部
JPanel center = new JPanel();             //创建面板对象center
center.setLayout(new GridLayout(1, 2));             //设置面板布局
center.add(inceAr);                 //将文本域添加到面板上
center.add(inced);
add(center, BorderLayout.CENTER);                 //设置面板布局
validate();                 //刷新
port = 9898;                 //设置端口号
try {
group = InetAddress.getByName("224.255.10.0");         //指定接收地址
socket = new MulticastSocket(port);             //绑定多点广播套接字
socket.joinGroup(group);             //加入广播组
} catch (Exception e) {
e.printStackTrace();             //输出异常信息
}
setBounds(100, 50, 360, 380);             //设置布局
setVisible(true);             //将窗体设置为显示状态
}
public void run() {             //run()方法
while (true) {
byte data[] = new byte[1024];             //创建byte数组
DatagramPacket packet = null;             //创建DatagramPacket对象
packet = new DatagramPacket(data, data.length, group, port); //待接收的数据包
try {
socket.receive(packet);                 //接收数据包
String message = new String(packet.getData(), 0, packet
.getLength());                 //获取数据包中内容
inceAr.setText("正在接收的内容:\n" + message); //将接收内容显示在文本域中
inced.append(message + "\n");             //每条信息为一行
} catch (Exception e) {
e.printStackTrace();             //输出异常信息
}
if (b == true) {             //当变量等于true时,退出循环
break;
}
}
}
public void actionPerformed(ActionEvent e) {         //单击事件
if (e.getSource() == ince) {             //单击按钮ince触发的事件
ince.setBackground(Color.red);             //设置按钮颜色
stop.setBackground(Color.yellow);
if (!(thread.isAlive())) {             //如线程不处于“新建状态”
thread = new Thread(this);                 //实例化Thread对象
}
thread.start();                 //启动线程
b = false;                 //设置变量值
}
if (e.getSource() == stop) {             //单击按钮stop触发的事件
ince.setBackground(Color.yellow);             //设置按钮颜色
stop.setBackground(Color.red);
b = true;                 //设置变量值s
}
}
public static void main(String[] args) {            //主方法
Receive rec = new Receive();             //创建本类对象
rec.setSize(460, 200);                 //设置窗体大下
}
}

解决方案 »

  1.   

    我也是菜鸟啊。向你代码学习啊。我试了一下,将接收程序的thread.start();  放到
    if (!(thread.isAlive())) { }中就行了耶.
                   
      

  2.   

    有个问题,想问问楼主,那个socket.receive(packet);方法,是否是阻塞读的?
    问题应该就出在这里。
    也就是说,当没有收到报文、或者报文没有接收完毕的时候,这个receive方法,是不会返回滴。
    那么,楼主下面的代码就不会被执行,尤其是那个if(b == true){break;},
    所以,这个线程在你按下“停止接收”按钮的时候,是无法终止滴。
    然后,再按“开始接收”按钮,其thread.isAlive()当然要返回true了。
    未终止的线程,其thread.isAlive()为true,并且thread.start();会抛上面楼主说的那个异常。
    因为,人家线程已经是运行状态了,你还让人家开始运行,当然要抛异常了。
      

  3.   

    解决这个问题的方法,最好是采用非阻塞的方式进行通信,
    每个循环都检测一次是否有数据,然后sleep几毫秒。
    不过,编程复杂度可能要加大一点。当然,也有比较恶心的做法。
    就是,后台线程还是死命的接受,
    前台只负责设置一个变量,控制程序是否显示(记录)这个接收的内容。
    这样,那个线程只在创建对象的时候start一下,其他的时候,根本不用管它。
      

  4.   

    您好!receive()按书上说的应该是阻塞的,但我发送程序是有间隔的发,不是一直发,那报文会接收完毕吧!这程序你给改正的方法吗?我是初学的,程序是书上的,对相关的知识都不足,请给出具体的讲解方法!
      

  5.   

    改进的方法,我在4楼已经说了,两个方式,你看着办吧。至于那个阻塞读的问题,我再介绍一下。不是读半包、粘包的问题。
    你发了一个报文,客户端会收一个报文,receive方法返回,做后续处理。
    然后,在你发下一个包之前,客户端已经执行到了receive方法,并且,线程阻塞在这个方法上了。
    如果服务端持续不发包,客户端的receive方法始终无法返回,那么,后续的代码根本运行不到。
    这时,你点那个“停止接收”,也就是把b变量设置为true,它并不会影响到那个break语句,
    以至于线程停止。因为,receive方法由于没有收到报文而在那阻塞着呢,所以,后面的代码执行不到。
    (就是,你在点了“停止接收”后,必须再收一个报文,才能让线程结束,
       如果你点了“停止接收”后,还没收到报文就又点了“开始接收”,那么就会抛异常)明白吧 ?
    再不明白,你另请高明吧。我尽力了。
      

  6.   

    不可能啊,我这儿运行正常啊。都能收到啊。
    要不你在发送的socket.joinGroup(iaddress); //加入广播组
    之前加上:socket.setBroadcast(true);试试。
      

  7.   

    首先很感谢您的再三回答!
    真的很详细,我说说我对您那些话的理解!
    如果我只按“开始接收”,不去按“停止接收”,程序应该是正常的,不会出错,原因是receive()接到数据包,返回,继续执行其它代码,因为b=false;所以一直在循环执行receive()(阻塞,发送,接收,阻塞,发送,接收……);
    但现在是我只按“开始接收”,却不能正常显示接收。
    您说的先按“开始接收”---“停止接收”---“开始接收”,程序真的是像你说的那样会抛出错误!
    您的改进思路是明白的,但两个方法都不懂得实现!如果我一直在拼命地receive()接收不是一样会遇到阻塞出错的问题(像上面的那种错),还有就是如何显示接收到的信息也不懂得怎么实现!
      

  8.   

    牛,学习中, 
    preferme说得对
      

  9.   

    能把你的代码源文件发给我吗?我想看看是不是代码还是什么问题,邮箱:[email protected]!谢谢~~
      

  10.   

    就是如下这个代码啊。在我机器上运行能接收到啊import java.io.IOException; //导入java.io.IOException类
    import java.net.*; //导入java.net包
    public class Weather extends Thread{ //创建类。该类为多线程执行程序
    String weather = "节目预报:八点有大型晚会,请收听";
    int port = 9898; //定义端口
    InetAddress iaddress = null; //创建InetAddress对象
    MulticastSocket socket = null; //声明多点广播套接字
    Weather(){ //构造方法
    try {
    iaddress = InetAddress.getByName("224.255.10.0"); //实例化InetAddress,指定地址
    socket = new MulticastSocket(port); //实例化多点广播套接字
    socket.setTimeToLive(1); //指定发送范围是本地网络
    socket.setBroadcast(true);
    socket.joinGroup(iaddress); //加入广播组
    } catch (Exception e) {
    e.printStackTrace(); //输出异常信息
    }
    }
    public void run(){ //run()方法
    while(true){
    DatagramPacket packet = null; //声明DatagramPacket对象
    byte data[] = weather.getBytes(); //声明字节数组
    packet = new DatagramPacket(data,data.length,iaddress,port); //将数据打包
    System.out.println(new String(data)); //将广播信息输出
    try {
    socket.send(packet); //发送数据
    sleep(3000); //线程休眠
    } catch (Exception e) {
    e.printStackTrace(); //输出异常信息
    }
    }
    }
    public static void main(String[] args) { // 主方法
    Weather w = new Weather(); //创建本类对象
    w.start(); //启动线程
    }

    import java.awt.event.*;             //导入java.awt.event包 
    import javax.swing.*; 
    import java.awt.*; 
    import java.net.*; 
    public class Receive extends JFrame implements Runnable, ActionListener { 
    int port;                 //定义int型变量 
    InetAddress group = null;             //声明InetAddress对象 
    MulticastSocket socket = null;             //创建多点广播套接字对象 
    JButton ince = new JButton("开始接收");             //创建按钮对象 
    JButton stop = new JButton("停止接收"); 
    JTextArea inceAr = new JTextArea(10, 10);             //显示接收广播的文本域 
    JTextArea inced = new JTextArea(10, 10); 
    Thread thread;                 //创建Thread对象 
    boolean b = false;                 //创建boolean型变量 
    public Receive() {                 //构造方法 
    super("广播数据报");             //调用父类方法 
    thread = new Thread(this); 
    ince.addActionListener(this);             //绑定按钮ince的单击事件 
    stop.addActionListener(this);             //绑定按钮stop的单击事件 
    inceAr.setForeground(Color.blue);             //指定文本域中文字颜色 
    JPanel north = new JPanel();             //创建Jpane对象 
    north.add(ince);                 //将按钮添加到面板north上 
    north.add(stop); 
    add(north, BorderLayout.NORTH);                 //将north放置在窗体的上部 
    JPanel center = new JPanel();             //创建面板对象center 
    center.setLayout(new GridLayout(1, 2));             //设置面板布局 
    center.add(inceAr);                 //将文本域添加到面板上 
    center.add(inced); 
    add(center, BorderLayout.CENTER);                 //设置面板布局 
    validate();                 //刷新 
    port = 9898;                 //设置端口号 
    try { 
    group = InetAddress.getByName("224.255.10.0");         //指定接收地址 
    socket = new MulticastSocket(port);             //绑定多点广播套接字 
    socket.joinGroup(group);             //加入广播组 
    } catch (Exception e) { 
    e.printStackTrace();             //输出异常信息 

    setBounds(100, 50, 360, 380);             //设置布局 
    setVisible(true);             //将窗体设置为显示状态 

    public void run() {             //run()方法 
    while (true) { 
    byte data[] = new byte[1024];             //创建byte数组 
    DatagramPacket packet = null;             //创建DatagramPacket对象 
    packet = new DatagramPacket(data, data.length, group, port); //待接收的数据包 
    try { 
    socket.receive(packet);                 //接收数据包 
    String message = new String(packet.getData(), 0, packet 
    .getLength());                 //获取数据包中内容 
    inceAr.setText("正在接收的内容:\n" + message+"\n"); //将接收内容显示在文本域中 
    inced.append(message + "\n");             //每条信息为一行 
    } catch (Exception e) { 
    e.printStackTrace();             //输出异常信息 

    if (b == true) {             //当变量等于true时,退出循环 
    break; 



    public void actionPerformed(ActionEvent e) {         //单击事件 
    if (e.getSource() == ince) {             //单击按钮ince触发的事件 
    ince.setBackground(Color.red);             //设置按钮颜色 
    stop.setBackground(Color.yellow); 
    if (!(thread.isAlive())) {             //如线程不处于“新建状态” 
    thread = new Thread(this); 
    thread.start(); //实例化Thread对象 

                   //启动线程 
    b = false;                 //设置变量值 

    if (e.getSource() == stop) {             //单击按钮stop触发的事件 
    ince.setBackground(Color.yellow);             //设置按钮颜色 
    stop.setBackground(Color.red); 
    b = true;                 //设置变量值s 


    public static void main(String[] args) {           //主方法 
    Receive rec = new Receive();             //创建本类对象 
    rec.setSize(460, 200);                 //设置窗体大下