UDP Multicast и Gui потоки

Модератор: Absurd

Ответить
michael
Сообщения: 116
Зарегистрирован: 15 июл 2004, 13:06
Откуда: ISRAEL (ранее - из Литвы)
Контактная информация:

Всем привет
Вот вопрос
Есть сервер что посылает по UDP рекламу по Multicast
Есть Gui на клиенте что ловит рекламу и отображает её.
Но хотя ю вижу что реклама приходит на клиент (отпечатываю в консуле) Gui полностью умерает. Вот код

Код: Выделить всё

package GUI;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.Socket;

import javax.swing.*;
import javax.swing.border.Border;

import Util.Controller;

import Common.ChatUser;

public class Chat extends JFrame 
{
	private Container surface;
	private JTextArea taOutpu;
	private JTextField tfInput;
	private DefaultListModel model;
	private JList 	lstClients;
	private JButton btnSend;
	private JLabel lblCommers;
	private String toAppend;
	private String currentPlayerName;
	
	
    public Chat(String PlayerName)
    {
    	this.currentPlayerName =PlayerName;
    	BorderLayout bl = new BorderLayout();
    	surface = this.getContentPane();
    	surface.setLayout(bl);
    	model = new DefaultListModel();
    	lstClients =new JList(model);
    	lstClients.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY));
    	model.addElement(new ChatUser("\\\\_otctpe/\\|-0_//","192.168.2.100"));
    	model.addElement(new ChatUser("test","192.168.2.100"));
    	btnSend = new JButton("Send");
    	btnSend.addActionListener(new ActionListener(){

			public void actionPerformed(ActionEvent e) {
				ChatUser	cu = (ChatUser)lstClients.getSelectedValue();
				try {
			          Socket socket = new Socket(cu.getIpAddress(), 3000);
			          ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
			         
			          appendText("You say: "+tfInput.getText()+"\n");
			          out.writeObject(currentPlayerName+" say: "+tfInput.getText()+"\n");

			          out.close();
			          
			          socket.close();
			      } catch (Exception e1) {
			          System.out.println(e1);
			      }
				
			}});
    	taOutpu = new JTextArea();
    	taOutpu.setLineWrap(true);
    	taOutpu.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY));
    	tfInput = new JTextField();
    	lblCommers = new JLabel();
    	JPanel pnlBottom = new JPanel(new BorderLayout());
    	pnlBottom.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
    	pnlBottom.add(BorderLayout.CENTER,tfInput);
    	pnlBottom.add(BorderLayout.EAST,btnSend);
    	surface.add(BorderLayout.SOUTH,pnlBottom);
    	surface.add(BorderLayout.CENTER,taOutpu);
    	surface.add(BorderLayout.EAST,lstClients);
    	surface.add(BorderLayout.NORTH,lblCommers);
    	this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    	this.setSize(543,340);
    	this.setLocation(WindowPositioner.Center(this));
    	this.setResizable(false);
    	this.setVisible(true);
    	
    	
    //start multicast sniffer
    	MulticastSniffer mcs = new MulticastSniffer(this);
    	mcs.start();

    	
    }
    public static void main(String [] s)
    {
    	new Chat("Michael");
    }
	
	public synchronized void appendText(String toAppend) 
	{
		
			taOutpu.append(toAppend);
			this.toAppend=null;
	}
	
	
	public void setAppendText(String toAppend)
	{
		this.toAppend = toAppend;
	}
}
class MulticastSniffer extends Thread
{
	MulticastSocket ms;
	Chat chat;
	
	//const'
	public MulticastSniffer(Chat chat)
	{
		this.chat = chat;
		try {
			ms = new MulticastSocket(3000);
			ms.joinGroup(InetAddress.getByName("230.0.0.1"));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	
	}
	public void run()
	{
		
		   
		while(true)
		{
			Runnable adder = new Runnable()
			{
				public void run()
				{
					 byte[] buffer = new byte[8192];
    			      while (true) 
    			      {
    			        DatagramPacket dp = new DatagramPacket(buffer, buffer.length);
    			        dp.setLength(buffer.length);
    			        try {
							ms.receive(dp);
						} catch (IOException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
    			        String s = new String(dp.getData(), 0, dp.getLength());
    			        System.out.println(s);
    			        chat.appendText(s);
    			      }
				}
			};
			
				try{
					SwingUtilities.invokeAndWait(adder);
				}
				catch(Exception e){
					System.out.println(e.getMessage());
				}
			
		}	// end while 
	}//end run
}
Аватара пользователя
Oscar
Сообщения: 963
Зарегистрирован: 29 май 2004, 13:44
Откуда: Мюнхен (рожден в Киеве)
Контактная информация:

Первая мысль:

michael, слишком много кода,
к тому же за неимением мультикаст сервера (даже если поставить, конфигурация будет иная)
не вижу возможности репродуцировать ошибку.

Совет: возьми профайлер и запусти через него свой чат, тогда дэдлок и увидишь.

Профайлер, например JProfiler, неделя trial, мне помог (сразу показал DeadLock именно в GUI).


P.S. у меня была ошибка в том, что я писал synchronized на методе,
а на самом деле надо было делать:

Код: Выделить всё

// ...
synchronized(getTreeLock()) {
	// код
}
// ...
мало ли .. может те же грабли .. в appendText




Вторая мысль: а что такое SwingUtilities.invokeAndWait и уверен ли ты, что правильно это используешь ?




Третья мысль:

Код: Выделить всё

while (true) { // загребает под себя все ресурсы, потому и висим
	// во избежание этой проблемы:
	
	// do something
	try {
		Thread.sleep(20);
	} catch (InterruptedException e) {
		e.printStackTrace();
		break;
	}
}


Четвёртая мысль:

Если MulticastSniffer уже extends Thread, тогда зачем внутри его run создавать ещё один Runnable ?
поищи на SUNе, как правильно создавать Threadы.
michael
Сообщения: 116
Зарегистрирован: 15 июл 2004, 13:06
Откуда: ISRAEL (ранее - из Литвы)
Контактная информация:

Ув. Оскар. Я обосновывался на следушем примере
The Thread-Safe way to update GUI

Код: Выделить всё

class AddingThread extends Thread{
		public void run(){
			for(int i = 0;i<10;i++){
				try{
					sleep(1000);
					Runnable adder = new Runnable(){
						public void run(){
							int num = Integer.parseInt(fld.getText().trim());
							num++;
							fld.setText(num + "");
						}
					};
					try{
						SwingUtilities.invokeAndWait(adder);
					}
					catch(Exception e){
					}
				}
				catch(InterruptedException e){
				}
			}
		}
	}
но как видно multicast как то влияет не потоки не понятеым мне способом, поэтому я решил проблему следущим способом

Код: Выделить всё

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;



public class TestWindow extends JFrame
{
	JLabel l = new JLabel("ddd");
	String packet;
	class MulticastSniffer extends Thread
	{
		MulticastSocket ms;
		
		
		//const'
		public MulticastSniffer()
		{
			
			try {
				ms = new MulticastSocket(3000);
				ms.joinGroup(InetAddress.getByName("230.0.0.1"));
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		
		}
		public void run()
		{
			
			
				 byte[] buffer = new byte[8192];
			      while (true) 
			      {
			        DatagramPacket dp = new DatagramPacket(buffer, buffer.length);
			        dp.setLength(buffer.length);
			        try {
						ms.receive(dp);
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
			        packet = new String(dp.getData(), 0, dp.getLength());
			        System.out.println(packet);
			     
				
			}	// end while 
		}//end run
	}//end recieve multicast
	class AddingThread extends Thread{
		public void run(){
			while(true){
				try{
					sleep(100);
					Runnable adder = new Runnable(){
						public void run(){
							l.setText(packet);
						}
					};
					try{
						SwingUtilities.invokeAndWait(adder);
					}
					catch(Exception e){
					}
				}
				catch(InterruptedException e){
				}
			}
		}
	}

   public TestWindow()
   {
	   setTitle("Bla bla");
	   getContentPane().add(new JPanel().add(l));
	   setVisible(true);
	   startUpdate();
   }
   public void startUpdate()
   {
	   MulticastSniffer m = new MulticastSniffer();
	   m.start();
	   AddingThread a = new AddingThread();
	   a.start();
   }
   public static void main(String [] s)
   {
	   new TestWindow();
   }
}


michael
Сообщения: 116
Зарегистрирован: 15 июл 2004, 13:06
Откуда: ISRAEL (ранее - из Литвы)
Контактная информация:

Черт, не то переписал
The Thread safe way to update thread

Код: Выделить всё

import java.awt.*;
import java.awt.event.*;
import java.lang.reflect.*;
import javax.swing.*;

public class InvokeWaitExample extends JFrame{
	JTextField fld   = new JTextField(14);
	JButton    addBt = new JButton("add");
	JLabel     pressAddBt = new JLabel("0");
	class AddingThread extends Thread{
		public void run(){
			for(int i = 0;i<10;i++){
				try{
					sleep(1000);
					Runnable adder = new Runnable(){
						public void run(){
							int num = Integer.parseInt(fld.getText().trim());
							num++;
							fld.setText(num + "");
						}
					};
					try{
						SwingUtilities.invokeAndWait(adder);
					}
					catch(Exception e){
					}
				}
				catch(InterruptedException e){
				}
			}
		}
	}
	public InvokeWaitExample(){
		arrangeGui();
		addListners();
		AddingThread trd = new AddingThread();
		trd.start();
	}
	public void arrangeGui(){
		Container c = getContentPane();
		fld.setText("0");
		c.setLayout(new GridLayout(0,2));
		c.add(new JLabel("all clicks"));
		c.add(fld);
		c.add(new JLabel("all button clicks"));
		c.add(pressAddBt);
		c.add(new JLabel("  "));
		c.add(addBt);

		pack();
	}
	public void addListners(){
		ActionListener adder = new ActionListener(){
			public void actionPerformed(ActionEvent ev){
				int num = Integer.parseInt(fld.getText().trim());
				num++;
				fld.setText(num + "");

				num = Integer.parseInt(pressAddBt.getText().trim());
				num++;
				pressAddBt.setText(num+"");


			}
		};
		addBt.addActionListener(adder);
	}
	public static void main(String[] args){
		InvokeWaitExample exmp1 = new InvokeWaitExample();
		exmp1.setVisible(true);
	}
}
Аватара пользователя
Oscar
Сообщения: 963
Зарегистрирован: 29 май 2004, 13:44
Откуда: Мюнхен (рожден в Киеве)
Контактная информация:

michael, в обоих приведённых примерах, а так же в окончательном решении,

в методе run есть вызов sleep, см. третью мысль.

В любом случае, рад, что проблема так быстро решилась.


Но насчёт "Thread safe" надо будет мне как-нить обязятельно почитать ...


P.S. Если можно, то без "уважаемый" и на "ты" :-)
michael
Сообщения: 116
Зарегистрирован: 15 июл 2004, 13:06
Откуда: ISRAEL (ранее - из Литвы)
Контактная информация:

Тогда просто спасибо
Ответить