Netzwerkprogrammierung

MaxK1990

Mitglied
Hey Leute,
ich bin gerade dabei ein kleines Spiel zu programmieren, in das ich auch einen Netzwerkmodus einbauen möchte. Jetzt habe ich mir aber erstmal ein kleines Nebenprojekt gemacht, in der ich überhaupt erstmal die Netzwerkprogrammierung lerne. Ich habe mir durch "Java ist auch eine Insel" und weiteren Seiten jetzt ein kleines Grundwissen angeeignet und kann schon von einem auf einen anderen PC eine Verbindung aufbauen und bei der Verbindung auch InputStream und OutputStream verwenden. Verschicke ich aber per Button nach dem Verbindungsaufbau einen Text (Button "Test senden") sagt er mir hier "Socket is closed". Das gleiche gilt auch für die Server-Seite. Ich habe auch schon versucht den InputStream auf dem Server & den OutputStream auf dem Client vor erst offen zu lassen, dann verheddert er sich aber in einer Endlosschleife.
Hier mal meine 2 Fachklassen, die ich derzeit habe. die GUI schicke ich vorerst mal nicht mit, da diese eigentlich recht irrelevant zum Aufbau ist.
Ich weiß, dass mein Stil noch recht ungeordnet ist, da ich noch Anfänger bin. Vielleicht versteht ihr trotzdem was ich meine und könnt mir helfen. Am liebsten wäre es mir, wenn ihr die "Unordnung" lasst, da es meine zur Zeit noch persönliche Ordnung ist und ich das Thema erstmal auf diese Weise verstehen möchte.

Danke MaxK1990



Klasse 1 (Server):

Code:
package paketFK;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

import javax.swing.JOptionPane;

public class Server {
	private ServerSocket server;
	private Socket client;
	private int port;
	
	public Server(int port){
		this.port = port;
	}
	
	public void serverErstellen(){
		try {
			server = new ServerSocket(this.port);
			client = server.accept();
			//JOptionPane.showMessageDialog(null, "Verbindung erfolgreich!");
		} 
		catch (IOException e) {
			JOptionPane.showMessageDialog(null, "Server nicht gestartet!");
			e.printStackTrace();
		}
	}
	
	public String update(){
		try {
			client = server.accept();
			 InputStream in = client.getInputStream();
		     StringBuffer buf = new StringBuffer();
		     int r;
	
		    while((r =in.read())!=-1){
		         buf.append((char)r);
	        }
	     
	        String nachricht = buf.toString();
	        System.out.println("Nachricht:" + nachricht);
	        in.close();
	        
	        return nachricht;
		}
		catch(IOException ex){
			System.out.println(ex.getMessage());
			System.out.println("Fehlgeschlagen!");
			return "Fehlgeschlagen!";
		}
	}
	
	public void serverStoppen(){
		try {
			server.close();
			JOptionPane.showMessageDialog(null, "Server gestoppt!");
		} catch (IOException e) {
			
		}
	}
	
}


Klasse 2 (Client):

Code:
package paketFK;

import java.io.*;
import java.net.Socket;

import javax.swing.JOptionPane;

public class Client {
	private String host;
	private int port;
	private Socket socket;
	private InputStream in;
	
	public void verbinden(String host, int port, String name){
		try {
			this.host = host;
			this.port = port;
			
			socket = new Socket( this.host , this.port );
			//JOptionPane.showMessageDialog(null, "Verbindung erfolgreich!");
			
		} catch (IOException e) {
			JOptionPane.showMessageDialog(null, "Verbindung fehlgeschlagen!");
		}
	}
	
	public void testSenden(String host, int port, String text){
		try{
			this.verbinden(this.host, this.port, "");
			
			this.in = socket.getInputStream();
			OutputStream out = socket.getOutputStream();
			
			byte data[] = text.getBytes();
			
			out.write(data);
			out.close();
			
			System.out.println("Versendet!");
		}
		catch(IOException ex){
			System.out.println(ex.getMessage());
		}
		
	}
}
 
Ich füge mal doch noch die beiden GUI-Fenster hinzu:

Klasse 3 (Clientfenster):

Code:
package paketGUI;

import java.awt.BorderLayout;
import javax.swing.JPanel;
import javax.swing.JFrame;
import javax.swing.JTextField;
import java.awt.Rectangle;
import javax.swing.JButton;

import paketFK.Client;
import java.awt.Dimension;

public class Clientfenster extends JFrame {

	private static final long serialVersionUID = 1L;
	private JPanel jContentPane = null;
	private JTextField txtIP = null;
	private JButton btnVerbinden = null;
	private Client c1 = new Client();
	private JTextField txtName = null;
	private JButton btnTest = null;
	private JTextField txtText = null;
	/**
	 * This is the default constructor
	 */
	public Clientfenster() {
		super();
		initialize();
	}

	/**
	 * This method initializes this
	 * 
	 * @return void
	 */
	private void initialize() {
		this.setSize(538, 200);
		this.setContentPane(getJContentPane());
		this.setTitle("Verbinden");
	}

	/**
	 * This method initializes jContentPane
	 * 
	 * @return javax.swing.JPanel
	 */
	private JPanel getJContentPane() {
		if (jContentPane == null) {
			jContentPane = new JPanel();
			jContentPane.setLayout(null);
			jContentPane.add(getTxtIP(), null);
			jContentPane.add(getBtnVerbinden(), null);
			jContentPane.add(getTxtName(), null);
			jContentPane.add(getBtnTest(), null);
			jContentPane.add(getTxtText(), null);
		}
		return jContentPane;
	}

	/**
	 * This method initializes txtIP	
	 * 	
	 * @return javax.swing.JTextField	
	 */
	private JTextField getTxtIP() {
		if (txtIP == null) {
			txtIP = new JTextField();
			txtIP.setBounds(new Rectangle(60, 38, 171, 49));
		}
		return txtIP;
	}

	/**
	 * This method initializes btnVerbinden	
	 * 	
	 * @return javax.swing.JButton	
	 */
	private JButton getBtnVerbinden() {
		if (btnVerbinden == null) {
			btnVerbinden = new JButton();
			btnVerbinden.setBounds(new Rectangle(13, 106, 117, 34));
			btnVerbinden.setText("Verbinden");
			btnVerbinden.addActionListener(new java.awt.event.ActionListener() {
				public void actionPerformed(java.awt.event.ActionEvent e) {
					c1.verbinden(txtIP.getText(),1111, txtName.getText());
				}
			});
		}
		return btnVerbinden;
	}

	/**
	 * This method initializes txtName	
	 * 	
	 * @return javax.swing.JTextField	
	 */
	private JTextField getTxtName() {
		if (txtName == null) {
			txtName = new JTextField();
			txtName.setBounds(new Rectangle(85, 5, 123, 30));
		}
		return txtName;
	}

	/**
	 * This method initializes btnTest	
	 * 	
	 * @return javax.swing.JButton	
	 */
	private JButton getBtnTest() {
		if (btnTest == null) {
			btnTest = new JButton();
			btnTest.setBounds(new Rectangle(321, 105, 109, 34));
			btnTest.setText("Text senden");
			btnTest.addActionListener(new java.awt.event.ActionListener() {
				public void actionPerformed(java.awt.event.ActionEvent e) {
					c1.testSenden(txtIP.getText(),1111,txtText.getText());
				}
			});
		}
		return btnTest;
	}

	/**
	 * This method initializes txtText	
	 * 	
	 * @return javax.swing.JTextField	
	 */
	private JTextField getTxtText() {
		if (txtText == null) {
			txtText = new JTextField();
			txtText.setBounds(new Rectangle(292, 27, 164, 56));
		}
		return txtText;
	}

}  //  @jve:decl-index=0:visual-constraint="10,10"


Klasse 4 (Serverfenster):

Code:
package paketGUI;

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

import paketFK.Server;

import java.awt.Rectangle;
import java.awt.Dimension;
import javax.swing.JLabel;

public class Serverfenster extends JFrame {

	private static final long serialVersionUID = 1L;
	private JPanel jContentPane = null;
	private JButton btnStarten = null;
	private Server s1;
	private JButton btnStop = null;
	private JLabel lblCha = null;
	private JButton btnUpdate = null;

	/**
	 * This is the default constructor
	 */
	public Serverfenster() {
		super();
		initialize();
	}

	/**
	 * This method initializes this
	 * 
	 * @return void
	 */
	private void initialize() {
		this.setSize(593, 200);
		this.setContentPane(getJContentPane());
		this.setTitle("JFrame");
	}

	/**
	 * This method initializes jContentPane
	 * 
	 * @return javax.swing.JPanel
	 */
	private JPanel getJContentPane() {
		if (jContentPane == null) {
			lblCha = new JLabel();
			lblCha.setBounds(new Rectangle(282, 11, 284, 140));
			lblCha.setText("");
			jContentPane = new JPanel();
			jContentPane.setLayout(null);
			jContentPane.add(getBtnStarten(), null);
			jContentPane.add(getBtnStop(), null);
			jContentPane.add(lblCha, null);
			jContentPane.add(getBtnUpdate(), null);
		}
		return jContentPane;
	}

	/**
	 * This method initializes btnStarten	
	 * 	
	 * @return javax.swing.JButton	
	 */
	private JButton getBtnStarten() {
		if (btnStarten == null) {
			btnStarten = new JButton();
			btnStarten.setBounds(new Rectangle(27, 19, 232, 93));
			btnStarten.setText("Starten");
			btnStarten.addActionListener(new java.awt.event.ActionListener() {
				public void actionPerformed(java.awt.event.ActionEvent e) {
					s1 = new Server(1111);
					s1.serverErstellen();
				}
			});
		}
		return btnStarten;
	}

	/**
	 * This method initializes btnStop	
	 * 	
	 * @return javax.swing.JButton	
	 */
	private JButton getBtnStop() {
		if (btnStop == null) {
			btnStop = new JButton();
			btnStop.setBounds(new Rectangle(28, 121, 107, 30));
			btnStop.setText("Stoppen");
			btnStop.addActionListener(new java.awt.event.ActionListener() {
				public void actionPerformed(java.awt.event.ActionEvent e) {
				s1.serverStoppen();
				}
			});
		}
		return btnStop;
	}

	/**
	 * This method initializes btnUpdate	
	 * 	
	 * @return javax.swing.JButton	
	 */
	private JButton getBtnUpdate() {
		if (btnUpdate == null) {
			btnUpdate = new JButton();
			btnUpdate.setBounds(new Rectangle(141, 119, 117, 32));
			btnUpdate.setText("Update");
			btnUpdate.addActionListener(new java.awt.event.ActionListener() {
				public void actionPerformed(java.awt.event.ActionEvent e) {
					lblCha.setText(s1.update());
				}
			});
		}
		return btnUpdate;
	}

}  //  @jve:decl-index=0:visual-constraint="10,10"
 
man sieht ... du hast keinen plan von GUI's und noch weniger von NETCODE

einfaches server/client beispiel

server
Java:
import java.io.*;
import java.net.*;
public class server
{
	public static void main(String[] args) throws Exception { new server(); }
	public server() throws Exception
	{
		ServerSocket ss=new ServerSocket(51073);
		while(true)
		{
			Socket cs=ss.accept();
			(new servercon(cs)).start();
		}
	}
}

class servercon extends Thread
{
	Socket cs=null;
	public servercon(Socket cs) { this.cs=cs; }
	public void run()
	{
		try
		{
			InputStream in=cs.getInputStream();
			OutputStream out=cs.getOutputStream();
			int read=0;
			byte[] buf=new byte[128];
			while((read=in.read(buf))!=-1)
			{
				out.write(buf, 0, read);
			}
		}
		catch(Exception e) { e.printStackTrace(); }
	}
}

client
Java:
import java.io.*;
import java.net.*;
public class client
{
	public static void main(String[] args) throws Exception { new client(); }
	public client() throws Exception
	{
		Socket sock=new Socket("127.0.0.1", 51073);
		InputStream in=sock.getInputStream();
		OutputStream out=sock.getOutputStream();
		(new clientthread(System.in, out)).start();
		(new clientthread(in, System.out)).start();
	}
}

class clientthread extends Thread
{
	InputStream in=null;
	OutputStream out=null;
	public clientthread(InputStream in, OutputStream out) { this.in=in; this.out=out; }
	public void run()
	{
		try
		{
			int read=0;
			byte[] buf=new byte[128];
			while((read=in.read(buf))!=-1)
			{
				out.write(buf, 0, read);
			}
		}
		catch(Exception e) { e.printStackTrace(); }
	}
}
ich weis ... is n sehr einfaches beispiel ... aber läuft und reicht um die grundlagen zu verstehen

und jetzt noch ne GUI drüberlegen ... nee ... darauf hab ich nich wirklich bock ...
wobei ... wenn du vorhast das als spiel zu machen solltest du natürlich beide seiten gleichberechtigt drin unterbringen ...
könnt ich dir zwar mal schnell als beispiel machen ... aber dann würd ich ja deine arbeit übernehmen ...
wie gesagt ... grund lagen haste hier jetzt ... mit zu arbeiten und an deinen code anzupassen ist jetzt deine aufgabe ... natürlich können und werden wir dir dabei helfen ... aber das einer oder mehrere hier dir alles vorkaut ... na ... obwohl ichs in n paar minuten schreiben könnte mach ichs mal nich um den lernfaktor noch zu erhalten
 
@Spike: Bitte nicht so unfreundlich
Der Code von Matisse & co ist auch nicht besser – und für einen Anfänger doch recht gut geschrieben.
 
na unfreundlich sollte mein post eigentlich nich sein ... war halt nur nich ganz bei mir als ichs geschrieben hab ... kann sein das es desshalb etwas schroff klingt ... tut mir ja auch leid wenns so rübergekommen is ... aber es war nicht beabsichtigt

ich hab jetzt wo ich mein kaffee und mein brötchen weg noch mal so drüber gekuggt und du hast recht ... so schlecht isses wirklich nich ... nur das es halt eine einmal-verbindung is und die schleifen fehlen ^^

ich find es schon recht anspruchsvoll sich als noch nicht ganz so guter programmieren *anfänger / fortgeschrittener* selbst ein projekt vorzunehmen wo man sich in netzwerktechnik , graphischen oberflächen und spiele-logik hineinsteigern muss ums zum laufen zu bekommen ...
aber halt wie schon gesagt : ich würde ruhig beide kommunikations-seiten einbauen und dann anstelle von zwei unterschiedlichen apps eine schreiben die beides beinhaltet ...
könntest ja zum beispiel so mit zwei buttons oder nem menü lösen wo du dann auswählen kannst ob server oder client und dann den entsprechenden teil laden / starten ...
kompliziert ist das nicht ... sind wirklich nur n paar zeilen ...

das was ich mir schon schwieriger vorstelle und wo ich erlich gesagt keinen ansatz hätte wäre die implementierung der spiele-logik welche über die verbindung synchronisiert werden muss ...
wenn man jetzt einen zentralen game-server hat und sich an diesen mehrer clients verbinden ist das noch alles halbwegs vorstellbar ... spiel-logik im server implementieren und dann die clients mit den informationen versorgen und synchronisieren ...
aber wie man das jetzt bei zwei gleichberechtigten apps macht und wie man steuert wer nun anfängt und welche bedingungen für einen gültigen zug erfüllt werden müssen ... da würde ich erlich gesagt dran scheitern ...
bin halt eher der spezialist für den netcode selbst und anbindung an ne datenbank ... und noch teilweise für das bereitstellen von schnittstellen für GUI und logik ... aber die implementierung dessen müssen dann andere übernehmen

bin zur zeit dabei mit n paar freunden n spiel zu entwickeln ... die technik bei uns ist allerdings das der zentrale game-server die gesamte spiel-logik übernimmt und die clients nur für das darstellen der informationen dienen ... aber bis auf den ziemlich weit unten liegenden netcode habe ich zum glügg keine weiteren einsatz gebiete ... das übernehmen dann die die sich damit besser auskennen als ich ... erklären mir was für schnittstellen gebraucht werden und ich versuche diese dann so bereitzustellen ... gibt dann meist einige workarounds weil der der für die logik zuständig is ne andere vorstellung der informationen hat als die beiden die die GUI der clients entwickeln ... meine paar zeilen code sind also das nadelöhr wo sich beide seiten einig werden müssen ... was manchmal echt schwer zu realisieren ist ...

zurück zum thema
das realisieren einer logik mit netcode die so variabel ist das sie mit sich selbst "spielen" kann ... also beim mehrfach-start des programmes die instanzen gleichberechtigt sind ... das is schon echt ne übung ... und würde bei mir an dem punkt aufhören wo ich dann die schnittstellen zur logik bereit stelle ...
was also netcode angeht kann ich dir echt gut helfen ... aber was sonst die anbindung an die logik und die implementierung dieser angeht ... da müssen die anderen helfen ... ich bin da leider überfragt
 
Zurück