Aplikacja serwer i wielu klientów

0

Nie mogę znaleźć błędu, dobrze jest gdy włączę pierwszego klienta, ale gdy włączę drugiego to ten pierwszy gdzieś mi znika. To znaczy mogę wysłać wiadomość z obu klientów do serwera ale nie mogę wysłać z serwera do pierwszego klienta, przechwytuje to drugi. Nie mam pojęcia dlaczego.

Serwer

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;




public class SerwerGUI extends JFrame
{
	private JButton wyślij = new JButton("Wyślij");
	protected static JTextArea tekstArea = new JTextArea();
	private JScrollPane scrollPane = new JScrollPane(tekstArea);
	private JPanel panel = new JPanel(null);
	private static ArrayList<ObsługaKlienta> lista = new ArrayList<ObsługaKlienta>();
	private static ServerSocket socket;
	private static Socket mojSocket;
	private static int IdDoNadania=0;

	SerwerGUI()
	{
		new Połącz();
		setTitle("Serwer");
		setSize(300, 400);
		add(panel);
		scrollPane.setBounds(0, 0, getWidth()-15, 300);
		panel.add(scrollPane);
		
		wyślij.setBounds(100, 320, 80, 30);
		panel.add(wyślij);
		wyślij.addActionListener(new ActionListener()
		{
			
			@Override
			public void actionPerformed(ActionEvent e)
			{
				// TODO Auto-generated method stub
				lista.get(0).wyślijKomunikat();
			}
		});
		setVisible(true);
		
	}
	/**
	 * @param args
	 */
	public static void main(String[] args)
	{
		// TODO Auto-generated method stub
		SerwerGUI serwer = new SerwerGUI();
		serwer.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}
	static class Połącz extends Thread
	{
		Połącz()
		{
			this.start();
			
		}
		public void run()
		{
			try
			{
				socket = new ServerSocket(8866);
			} catch (IOException e)
			{
				// TODO Auto-generated catch block
				tekstArea.append("Błąd: Nie można utworzyć Socketu\n");
				
			}
			while (true)
			{
				try
				{
					mojSocket = socket.accept();
				} catch (IOException e)
				{
					// TODO Auto-generated catch block
					
					tekstArea.append("Błąd: Nie można utworzyć nowego połączenia\n");
				}

				lista.add(new ObsługaKlienta(mojSocket));
				tekstArea.append("Rozmiar listy: "+Integer.toString(lista.size())+"\n");

			}
		}
	}
	
	
	
	private static class ObsługaKlienta extends Thread
	{
		Socket kopiaMojSocket;
		static ObjectInputStream in = null;
		static ObjectOutputStream out = null;
		static String incoming = null;

		public ObsługaKlienta(Socket mojSocket)
		{
			// TODO Auto-generated constructor stub
			kopiaMojSocket = mojSocket;
			this.start();
			
		}

	

		public void run()
		{

			try
			{
				in = new ObjectInputStream(kopiaMojSocket.getInputStream());
			} catch (IOException e)
			{
				// TODO Auto-generated catch block
				tekstArea.append("Błąd: Nie można utworzyć strumienia wejściowego\n");
			}
			try
			{
				out = new ObjectOutputStream(kopiaMojSocket.getOutputStream());
			} catch (IOException e)
			{
				// TODO Auto-generated catch block
				tekstArea.append("Błąd: Nie można utworzyć strumienia wyjściowego\n");
			}

			new Odbieranie();
			wyślijID();
		}

		public static void wyślijID()
		{
			try
			{
				out.writeObject(String.valueOf(IdDoNadania));
				++IdDoNadania;
			} catch (IOException e)
			{
				// TODO Auto-generated catch block
				tekstArea.append("Błąd: Nie można wysłać Id\n");
			}
		}
		public static void wyślijKomunikat()
		{
			try
			{
				out.writeObject("Hello world");
				
			} catch (IOException e)
			{
				// TODO Auto-generated catch block
				tekstArea.append("Błąd: Nie można wysłać komunikatu\n");
				
			}
		}

		static class Odbieranie extends Thread
		{
			Odbieranie()
			{
				this.start();
			}

			public void run()
			{
				while (true)
				{
					try
					{
						incoming = (String) in.readObject();
					} catch (ClassNotFoundException | IOException e1)
					{
						// TODO Auto-generated catch block
						tekstArea.append("Błąd: Nie można odebrać komunikatu\n");
						break;
					}
					tekstArea.append("Od klienta: "+incoming+"\n");
					
				}
			}
		}
	}

}

Klient

package SerwerIKlientTestowy;

import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.LayoutManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

public class KlientGUI extends JFrame
{
	static JTextArea tekstArea = new JTextArea();
	JScrollPane scrollPane = new JScrollPane(tekstArea);
	static int id=-1;
	Socket mojSocket;

	JButton wyslij;
	MyPanel panel;
	ObjectOutputStream out;
	static ObjectInputStream in;
	KlientGUI()
	{
		
		socket();
		new Odbieranie();
		setSize(300,400);
		setTitle("Klient");
		panel = new MyPanel();
		panel.setLayout(null);
		
		
		
		
		panel.add(wyslij = new JButton("Wyślij"));
		wyslij.setBounds(100, 320, 80, 30);
		wyslij.addActionListener(new ActionListener()
		{
			
			@Override
			public void actionPerformed(ActionEvent arg0)
			{
				// TODO Auto-generated method stub
				wyślij();
				//komunikat.setText("ad");
			}
		});
		scrollPane.setSize(getWidth()-20, 300);
		
		panel.add(scrollPane);
		
		
		add(panel);
		setVisible(true);
	}

	public static void main(String[] args)
	{
		// TODO Auto-generated method stub
		new KlientGUI().setDefaultCloseOperation(EXIT_ON_CLOSE);
	}
	
	class MyPanel extends JPanel
	{
		MyPanel()
		{
			super();
		}
		public void paintComponent(Graphics g)
		{
			super.paintComponents(g);			
		}
	}

	private void socket() 
	{
		try
		{
			mojSocket = new Socket("localhost", 8866);
		} catch (UnknownHostException e)
		{
			// TODO Auto-generated catch block
			tekstArea.append("Błąd: Nie można utworzyć Socketu1\n");
		} catch (IOException e)
		{
			// TODO Auto-generated catch block
			tekstArea.append("Błąd: Nie można utworzyć Socketu2\n");
		}
		try
		{
			out = new ObjectOutputStream(mojSocket.getOutputStream());
		} catch (IOException e)
		{
			// TODO Auto-generated catch block
			tekstArea.append("Błąd: Nie można utworzyć strumienia wyjściowego\n");
		}
		try
		{
			in = new ObjectInputStream(mojSocket.getInputStream());
		} catch (IOException e)
		{
			// TODO Auto-generated catch block
			tekstArea.append("Błąd: Nie można utworzyć strumienia wejściowego\n");
		}
	}
	
	static class Odbieranie extends Thread
	{
		String incoming = null;
		Odbieranie()
		{
			this.start();
		}

		public void run()
		{
			odbiórID();
			while (true)
			{
				incoming=null;
				try
				{
					incoming = (String) in.readObject();
				} catch (ClassNotFoundException | IOException e1)
				{
					// TODO Auto-generated catch block
					tekstArea.append("Błąd: Nie można odebrać obiektu\n");
				
				}
				//System.out.println(incoming);
				tekstArea.append("Serwer: "+incoming+"\n");
			}
		}
		private void odbiórID()
		{
			try
			{
				incoming = (String) in.readObject();
			} catch (ClassNotFoundException | IOException e1)
			{
				// TODO Auto-generated catch block
				tekstArea.append("Błąd: Nie można odebrać Id\n");
			
			}
			tekstArea.append("ID= "+incoming+"\n");
			id=Integer.parseInt(incoming);
			
		}
	}
	
	private void wyślij()
	{
		try
		{
			out.writeObject("Id = "+id+" Hello World");
		} catch (IOException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

}
0

Ten kod to jeden wielki WTF. Aż dziw bierze ze da sie takie "coś" w Javie napisać.
Błąd polega na tym, że nie myślisz. Masz w serwerze JEDEN socket dla klientów. Siłą rzeczy tylko JEDEN klient może się u ciebie komunikować z serwerem. Jak dołącza się nowy klient to serwer o starym zapomina...
Ale tak zupełnie poważnie: wywal ten kod i zapomnij że kiedykolwiek coś takiego popełniłeś.

  • nazwy klas i metod po polsku i to ze znakami specjalnymi -> o_O
  • kod z serii apocalypse ready (otaczanie każdej linijki przez try catch) -> o_O
  • klasy statyczne -> o_O
  • mieszanie UI z logiką -> o_O
0

Ok, nie wiedziałem że musi być nowy socket dla każdego klienta, albo źle zrozumiałem jakiś tutorial albo zły tutorial widziałem. Chyba nie muszę mówić że dopiero się uczę, bo to widać. Każdy socket misi mieć inny port? .. z resztą i tak zaraz to sprawdzę.

0

Otwierasz socket TCP na konkretnym porcie u siebie, ale każde połączenie, to jego nowa "instancja" (z innym urządzeniem/portem po drugiej stronie kabla). Skopiuj na żywca przykład wielowątkowego serwera ze strony Oracle, a później zmień tak, żeby spełniało Twoje wymagania.

PS. Jak na to patrzę, to przypomina mi się "a kiedy mi smutno, statyczny konstruktor utworzę w edytorze"...

0

Hmmm najlepiej zapoznać się z dokumentacją i krok po kroku, dowiadywac się zasady działania serwera i klientów.
Poniżej przesyłam, krótki chodz dośc prosty przewodnik na temat soketów w javie:
http://docs.oracle.com/javase/tutorial/networking/sockets/index.html
Tutaj kolejny tutorial:
http://ashishmyles.com/tutorials/tcpchat/

Powinno trochę pomóc, później obczaje Twój magiczny kod, no chyba, że sam zobaczysz błędy, które w skrócie opisał @Shalom

0

Już myślę że wiem jakie błędy zrobiłem, przynajmniej część z nich. Po różnych tutorialach chodzę od 3 dni i chciałem sam to napisać, najpierw napisałem to bez GUI i tam wszystko się działo w main() stąd wszystkie klasy musiałem tworzyć statyczne.

A, i co przeszkadzają te bloki try/catch? Wstawiam je tam gdzie eclipse chce.

0
dam1an napisał(a):

A, i co przeszkadzają te bloki try/catch? Wstawiam je tam gdzie eclipse chce.

Same bloki try..catch nie są złe. Złe jest to że wstawiasz je bezmyślnie! Programowanie nie polega na wstawianiu losowych kawałków kodu "żeby IDE nie krzyczało", tylko na pisaniu kodu ze zrozumieniem. W ogóle dobrą praktyką jest uczyć się podstaw bez użycia IDE, żeby potem nie robić takich cudów na kiju.
U ciebie te wyjątki w ten sposób łapane nie mają sensu. Bo jak się sypnie 1 linijka metody to ty sobie wesoło zalogujesz błąd a potem... przejdziesz do kolejnej linijki, która sypnąć się musi skoro 1 się wysypała i tak dalej. Poprawnie w takiej sytuacji powinieneś złapać wyjątek dopiero pod koniec takiej metody i zalogować błąd.

1 użytkowników online, w tym zalogowanych: 0, gości: 1