[Gelöst - Java] Netzwerkprogrammierung für die Schule

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Antworten
Tejio
Establishment
Beiträge: 107
Registriert: 11.11.2010, 11:33

[Gelöst - Java] Netzwerkprogrammierung für die Schule

Beitrag von Tejio »

Hallo, alle zusammen ;)

ich komme heute mit einer Frage in Java zu euch. Es geht, wie der Betreff des Themas bereits mitteilt, um Netzwerkprogrammierung mit Multithreading. Es ist eine Aufgabe für die Schule.
Für die Aufgabe liegt ein Archiv mit einigen Tests vor. Prinzipiell gelingen meinem Partner und mir die meisten Tests, mit Ausnahme der letzten drei (Genau genommen sind es test3, test4 und test6 im Test BasicTestRemote.java). Dieser Test beschäftigt sich mit der eigentlichen Netzwerkprogrammierung.

Nun, um zu meiner eigentlichen Frage zu kommen:
In welcher Situation würde es zu einer SocketException (Address already in use) kommen?
Ich erstelle mir ein Server-Objekt und beim Binden des Sockets an den Port wird die Exception ausgelöst. Davor wurden alle vorherigen Server-Objekt schlafen gelegt.

Hier habe ich die Serverimplementierung:

Code: Alles auswählen

import java.util.List;

import java.net.Socket;
import java.net.ServerSocket;
import java.net.BindException;
import java.net.SocketException;

import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;

import network.Logger;
import network.LoggerImpl;

/**
 * Ein Server der per TCP-Verbindung die Berechnung von Primzahlen ermoeglicht.
 */
public class PrimeServerImpl implements PrimeServer
{
  private int clientNumber;

  /** Prozess zum Verwalten der Clients. */
  private PrimeServerProcess process;

  /** Verwaltungssocket. */
  private ServerSocket serverSocket;

  /** Logger für den Server. */
  private Logger serverLog;

  /**
   * Startet den Server. Diese Methode muss sofort zurueckkehren.
   * 
   * Fuer jede Clientverbindung wird ein eigener Thread gestartet.
   * 
   * @param port
   *          tcp port
   * @throws IOException
   *           Netzwerkfehler
   */
  public void startServer(int port) throws IOException
  {
    clientNumber=1;
    serverLog = new LoggerImpl();
    try {
      serverSocket = new ServerSocket(port);

      process = new PrimeServerProcess();
      process.enable();
      final Thread workerThread = new Thread(process);
      workerThread.start();

    } catch (BindException ex) {
      ex.printStackTrace();
    }

    /*
     * out.flush();
     */
  }

  /**
   * Stoppt den Server. Das bedeutet es werden keine neuen Verbindungen mehr
   * angenommen. Bereits bestehende Verbindungen laufen normal weiter. Die
   * Methode kehrt jedoch erst zurueck, wenn alle Clients die Verbindung beendet
   * haben.
   * 
   * @throws IOException
   *           Netzwerkfehler
   * @throws InterruptedException
   *           falls beim Beenden ein Netzwerkfehler auftritt
   */
  public void stopServer() throws IOException, InterruptedException
  {
    if (serverSocket != null) {
      process.disable();
      try {
        // serverSocket.setReuseAddress(true);
        serverSocket.close();
      } catch (BindException ex) {
        ex.printStackTrace();
      }
    }
    addEntry("client disconnected,1");
  }

  /**
   * 
   * @param e
   *          wird ans Ende des Logs hinzugefuegt.
   */
  public void addEntry(String e)
  {
    if (serverLog != null) {
      serverLog.addEntry(e);
    }
  }

  /**
   * 
   * @return Liefert eine Kopie des aktuellen Logs zurueck.
   */
  public List < String > getLog()
  {
    return serverLog.getLog();
  }

  /**
   * Verwaltet den Umgang mit den Clients.
   */
  private class PrimeServerProcess implements Runnable
  {
    /** Flag zur Überprüfung der Verbindung. */
    private boolean connected;

    /** Aktiviert die Überprüfung für neue Clients. */
    public void enable()
    {
      connected = true;
    }

    /** Deaktiviert die Überprüfung für neue Clients. */
    public void disable()
    {
      connected = false;
    }

    /**
     * Threading Funktion.
     */
    @Override
    public void run()
    {
      try {
        while (connected) {
          final PrimeServerSession session = new PrimeServerSession();

          try{
            session.connectWith(servSocket.accept());
          } catch (SocketException e) {
            return;
          }

          addEntry("client connected,1");
          final Thread t = new Thread(session);
          t.start();
        }
      }catch (IOException e) {
        return;
      }
    }
  }

  /** Session pro Client. */
  private class PrimeServerSession implements Runnable
  {
    /** Socket zur Client-Kommunikation. */
    private Socket socket;

    /** Outputstream für den Socket. */
    private ObjectOutputStream out;

    /** InputStream vom Socket. */
    private ObjectInputStream in;

    /**
     * Verbindet den Server mit einem Client.
     * 
     * @param socket
     *          Socket zur Kommunikation zu einem Client.
     */
    public void connectWith(Socket socket)
    {
      this.socket = socket;
      try {
        out = new ObjectOutputStream(socket.getOutputStream());
        out.flush();
        in = new ObjectInputStream(socket.getInputStream());
      } catch (IOException io) {
        io.printStackTrace();
      }
    }

    /**
     * Diese Funktion wird in einem Thread ausgeführt.
     */
    @Override
    public void run()
    {
      if (socket == null) {
        return;
      }

      String message;
      while (true) {
        try {
          out.writeObject("1");

        } catch (IOException ioException) {
          return;

        }
        try {
          message = (String) in.readObject();
          addEntry(message);
        } catch (IOException e) {
          e.printStackTrace();
        } catch (ClassNotFoundException e) {
          return;
        }

      }
    }

    /**
     * 
     */
    private void waitNow()
    {
      try {
        wait();
      } catch (InterruptedException e) {
        assert(false);
      }
    }

  }

}
Zuletzt geändert von Tejio am 07.07.2011, 17:25, insgesamt 2-mal geändert.
Benutzeravatar
Chromanoid
Moderator
Beiträge: 4259
Registriert: 16.10.2002, 19:39
Echter Name: Christian Kulenkampff
Wohnort: Lüneburg

Re: [Java] Netzwerkprogrammierung für die Schule

Beitrag von Chromanoid »

"Address already in use" kommt eigentlich nur wenn der port schon gebunden ist. Sicher dass nicht schon ein Test früher fehlschlägt und der Server nicht runtergefahren wird? Die Asserts finden nämlich teilweise vor dem Runterfahren statt...

Achja noch was: euer addEntry("client connected,1"); usw. kommt mir seltsam vor ich glaube, da soll eigentlich die client Nummer hinten ran. Das kann der Grund für das Fehlschlagen des 6. Tests sein. Schaut euch insgesamt noch mal euer logging an.
Jaw
Beiträge: 54
Registriert: 14.07.2004, 01:00
Wohnort: Raum Düsseldorf

Re: [Java] Netzwerkprogrammierung für die Schule

Beitrag von Jaw »

Ja das was die Meldung sagst stimmt schon. Ihr habt entweder den Socket oder ServerSocket auf dem jeweiligen Port bereits offen. Ich glaube es müsste eher der ServerSocket sein, da man mehrere Sockets mit einem Port verbinden kann. Die Zeilenangabe der Fehlermeldung verrät euch ja die Stelle wos vorkommt. Irgendwo vorher fehlt euch wohl dann das close dazu. Könnt euch ja mal Ausgaben bei öffnen und schließen machen und sehn, ob zwei mal Öffnen ohne Schließen dazwischen kommt.
Tejio
Establishment
Beiträge: 107
Registriert: 11.11.2010, 11:33

Re: [Java] Netzwerkprogrammierung für die Schule

Beitrag von Tejio »

Hallo zusammen!

@Jaw und @Chromanoid:
Danke für eure Antworten. Der Fehler lag an einer ganz anderen Stelle. Es war ein logischer Fehler. In einer Menge von Tests wird der Server immer wieder gestartet und gestoppt. Während er in der Kommunikation mit dem Client ist und die Session noch kein definiertes Ende gefunden hat, wird der Server beendet. Der Fehler lag darin, dass der Server eigentlich warten muss, bis alle Sessions fertig sind mit der Datenverarbeitung und ihre Zustimmung entsprechend gaben.

Ja, es stimmt, die Nummer sollte eigentlich hinten ran geklatscht werden, aber solange die Verbindung nicht richtig steht, bringt es mir noch nichts. Ich liebe Multithreading und Netzwerkprogrammierung...

Vielen Dank nochmal!

Gruß,
Teji
Antworten