Toon posts:

[Java] Server stilzetten via GUI

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik ben wat aan het oefenenen met sockets. Het is me gelukt om kleine client/server toepassingen maken. Nu wou ik een chat programma maken incl. server.

De server heb ik een kleine gui gegeven. Via een knopje gaat ie z'n serversocket maken en gaat ie luisteren. Ik had graag dat wanneer ik opnieuw op het knopje druk, de server stopt met luisteren.
Dit lukt me echter niet. Als ik de thread stop met stop(), stop de thread precies, maar blijft de poort open.

Weet iemand hoe ik dat kan oplossen?
De volledige code kun je hier vinden:
[url=#]Server[/url]
[url=#]ServerMain[/url]
[url=#]ServerModel[/url]
[url=#]ServerView[/url]

We moeten van school zo'n Model-View approach gebruiken, vandaar al die verschillende files.

Als er ook opmerkingen zijn, laat maar komen :)
Dan weet ik of ik goed/slecht bezig ben.

[ Voor 13% gewijzigd door Verwijderd op 14-03-2003 17:56 . Reden: Oude en foute source verwijderd ]


  • esf
  • Registratie: Juni 2002
  • Laatst online: 11-03 14:06

esf

Moet je naast svrConn.close(); niet ook socket.close(); aanroepen?

Ik heb voor m'n studie ook eens een keer een netwerkversie van pong moeten maken en daarbij hadden we een zelfde soort probleem. We stopten de thread maar als we weer een nieuwe aan wilden maken deed ie dat niet. Wat we toen hebben gedaan is:
De sockets sluiten
De run-loop van de thread afsluiten
alle verwijzingen van en naar de thread op null zetten
garbage collector aanroepen met gc();

succes

[ Voor 76% gewijzigd door esf op 12-03-2003 12:06 ]

The hardest thing in the world to understand is the income tax. - Albert Einstein


Verwijderd

Topicstarter
Bedankt voor je reply. SvrConn.close() is voldoende.

Ik heb nu ServerModel.java aangepast zoadat er geen finally { } volgt na try { } catch { } in de run method.
Nu kan ik de socket correct afsluiten, maar als ik opnieuw op connect druk, opent hij port 7000 niet meer. Ik vind het nogal vaag :-/

De nieuwe source code is ook geupload als iemand een kijkje wil nemen.

[ Voor 12% gewijzigd door Verwijderd op 12-03-2003 16:49 . Reden: Source Code ook geüpload ]


Verwijderd

In principe hoeft je ServerModel geen Thead te zijn. Je GUI reageert op events dus die heeft er geen last van. En je Sockets hebben er ook geen probleem mee want die zijn zelf een Thread.

  • esf
  • Registratie: Juni 2002
  • Laatst online: 11-03 14:06

esf

je kan met netstat -all kijken of de poort nog open staat... Dan weet je dat het aan de socket ligt. Anders zou het misschien kunnen dat de thread nog niet goed is afgesloten..

The hardest thing in the world to understand is the income tax. - Albert Einstein


Verwijderd

Topicstarter
Dat is het net. Als ik de server stop, dan is de poort ook effectief dicht, maar als ik dan opnieuw op connect druk, kan ie de poort niet meer openen.

  • esf
  • Registratie: Juni 2002
  • Laatst online: 11-03 14:06

esf

probeer
Java:
1
2
System.gc ();
System.runFinalization ();

eens aan te roepen.. Misschien dat bepaalde objecten nog niet goed zijn opgeruimd door de garbage collector.. Zoals ik in mijn eerste post zei heb ik dit nodig gehad bij een soortgelijk probleem dat ik had..

[ Voor 3% gewijzigd door esf op 14-03-2003 07:53 ]

The hardest thing in the world to understand is the income tax. - Albert Einstein


Verwijderd

Topicstarter
Met je stukje code krijg ik dit:
code:
1
TCP    quatre:7000            quatre:0               LISTENING
tijdens het runnen.

Als een portscanner (sfind) is langsgekomen:
code:
1
TCP    quatre:7000            localhost:2098         CLOSE_WAIT


Als ik dan op Disconnect druk, blijft dit hetzelfde.
Ik heb daarna nog eens op Connect gedrukt en krijg
code:
1
2
3
TCP    quatre:7000            quatre:0               LISTENING
TCP    quatre:2098            localhost:7000         FIN_WAIT_2
TCP    quatre:7000            localhost:2098         CLOSE_WAIT


Die 2098 is van die sfind. Volgens mij is er een probleem met sockets zelf?

Sluit ik het programma volledig, dan is poort 7000 volledig dicht.

De output in de JTextArea ziet er als volgt uit:
code:
1
2
3
4
5
6
7
8
9
Controller started.
Starting connection...
Trying...
Socket[addr=/127.0.0.1,port=2100,localport=7000] connected
Connection closed
Starting connection...
Connection closed
Starting connection...
Connection closed


Ik denk dat de run() method niet 100% is, omdat Trying... niet meer verschijnt wanneer ik op Connect druk, zoals de eerste keer.

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public void run() {
        try {
            svrConn = null;
            svrConn = new ServerSocket(7000);
            peer.setStatus("Trying...");
            while(true) {
                socket = svrConn.accept();
                String msg = (socket + " connected");
                peer.setStatus(msg);
                // Moet nog geïmplementeerd worden!
                //new SocketThread(socket).start();
            }
        }
        catch(IOException ioe) {
        }
        //finally {
        //}
    }


Waar moeten die garbage collector functies eigenlijk staan. Ik heb dit nog nooit eerder gebruikt.

Momenteel staan ze in:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void stopServer() {
        this.stop();
        try {
                System.out.println("Enter method stopServer()");    
                svrConn.close();
                socket.close();
                System.out.println("svrConn Closed");
                peer.setStatus("Connection closed");
                System.out.println("Exit mehod stopServer()");    
                System.gc(); 
                System.runFinalization();
        }
        catch(IOException ioe) {
        }
    }

  • esf
  • Registratie: Juni 2002
  • Laatst online: 11-03 14:06

esf

Sorry ik had je verkeerd begrepen denk ik. Wij sloten de gehele thread af als we de server stopten en startten hem weer opnieuw op als we opnieuw gingen connecten. Dit omdat we een spel maakten waarbij we zowel als host als als client konden spelen. Hiervoor was het afsluiten van de thread nodig, maar ik denk niet dat het nu nodig is.

Kijk in ieder geval even naar de run methode en wat je er mee doet. Ik denk dat je iets moet hebben als:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public void run()
{
    while (true)
    {
        if (!interrupted)
        {
            /* Server started */
            try
            {
                /* ongeveer wat jij in de run methode had
                inclusief de while(true) methode, maar die moet
                je hernoemen naar while(!interrupted) */
            }
            catch (IOException ioe) {}
            /* Server stopped */
        }
    }
    stopServer();
}

Dan moet je alleen aan het begin de methode start(); uitvoeren van de thread en voor de rest alleen werken met de boolean interrupted die in de while(!interrupted) staat in de run methode. Ik heb het snel even getypt dus er kunnen fouten in zitten , maar het moet volgens mij iets zijn als dit..

[ Voor 5% gewijzigd door esf op 14-03-2003 12:48 ]

The hardest thing in the world to understand is the income tax. - Albert Einstein


Verwijderd

Topicstarter
Thx :)
Ik zal het deze avond eens uitproberen als ik thuis kom.

Verwijderd

Topicstarter
Dag esf :)

Het is me gelukt om de thread correct te stoppen.
Om het te illustreren heb ik een dom programmaatje in elkaar gezet met een Model-View approach:

Server.java
Java:
1
2
3
public interface Server {
    public void setStatus(String status);
}


ServerMain.java
Java:
1
2
3
4
5
6
7
public class ServerMian {

    public static void main(String[] args) {
        ServerModel server = new ServerModel();
        ServerView gui = new ServerView(server);
    }
}


ServerModel.java
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class ServerModel {
    
    private Server peer;
    private volatile Thread serverThread;
    
    public ServerModel() {
    }
    
    public void startServer() {
        serverThread = new ChatServer();
        peer.setStatus("Thread Started.\n");
        serverThread.start();
    }
    
    public void stopServer() {
        serverThread = null;
        peer.setStatus("Thread stopped.\n");
    }
    
    public void setPeer(Server peer) {
        this.peer = peer;
    }
    
    public class ChatServer extends Thread {
        public ChatServer() {
        }
        
        public void run() {
            Thread thisThread = Thread.currentThread();
            while(serverThread == thisThread) {
                peer.setStatus("Thread Running...\n");
                try {
                    Thread.currentThread().sleep(2000);
                } 
                catch (InterruptedException e) {
                }
            }
        }
    }
}


ServerView.java
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class ServerView extends JFrame implements Server {
    
    private JButton controlButton;
    private JTextArea statusTextArea;
    private JLabel infoLabel;
    private JScrollPane statusScrollPane;
    private ServerModel model;
    private boolean online;
    
    public ServerView(ServerModel model) {
        super("Server");
        this.model = model;
        model.setPeer(this);
        online = false;
        
        getContentPane().setLayout(new BorderLayout());
        
        controlButton = new JButton("Connect");
        controlButton.addActionListener(new EventHandler());
        getContentPane().add(controlButton, BorderLayout.NORTH);
        
        statusTextArea = new JTextArea("User Interface Initialized.\n");
        statusScrollPane = new JScrollPane(statusTextArea);
        getContentPane().add(statusScrollPane, BorderLayout.CENTER);
        
        infoLabel = new JLabel("Quatre (c) 2003");
        getContentPane().add(infoLabel, BorderLayout.SOUTH);
                        
        this.setDefaultCloseOperation(3);
        this.setSize(420,400);
        this.setVisible(true);
    }
    
    public void setStatus(String status) {
        statusTextArea.append(status);
        statusTextArea.setCaretPosition(statusTextArea.getDocument().getLength());
    }
    
    public class EventHandler implements ActionListener {
        public void actionPerformed(ActionEvent ae) {
            if(!online) {
                model.startServer();
                controlButton.setText("Disconnect");
                online = true;
            }
            else {
                model.stopServer();
                controlButton.setText("Connect");
                online = false; 
            }
        }
    }
}


Hopelijk hebben andere mensen er ook wat aan ^^

Om de source code te downloaden, mag je hier klikken.
PGP Signature: hier.

Verwijderd

De ChatServer op null zetten is leuk gevonden alleen niet echt netjes.
Ik zou een method toevoegen op ChatServer genaamd stop().
Deze methode zou een variabele "private boolean mustRun" op false moeten zetten.
Het voordeel van deze method is dat je applicatie nog steeds een referentie heeft naar de ChatServer zodat hij kan checken of hij al gestopt is...(en er eventueel op wachten).

Die garbage collection en finalizers aanroepen is trouwens ook niet netjes.
In principe is dat nooit nodig en hoeft de JVM dat ook niet echt uit te voeren.
Volgens de Java spec is het alleen een hint naar de JVM dat je dat graag zou willen.
Belangrijk is dat je zeker weet dat er een serverSocket.close() is aangeroepen.
Daar moet je applicatie op wachten voordat hij echt zegt dat hij geclosed is.
Dat wachten kan je bijvoorbeeld doen door de stop() methode pas te laten returnen als je zeker dat de ServerSocket geclosed is.

  • esf
  • Registratie: Juni 2002
  • Laatst online: 11-03 14:06

esf

Dit is nog steeds niet helemaal wat ik bedoelde. Volgens komt de uitleg van Bierdopje daar een beetje in de buurt. Maar volgens mij is het nog wel nodig om een oneindige loop eromheen te maken zodat de thread niet wordt afgesloten maar alleen de loop waarin wordt gewacht of er nog nieuwe clients willen connecten. Maar als het werkt is het goed :)

Dat van de garbage collector en finalize was in ons geval nodig omdat de garbage collector eens in de zoveel tijd wordt uitgevoerd en wij onze thread op de een of andere manier niet helemaal konden verwijderen. Als wij weer een nieuwe instantie van de thread wilden maken (het diende als server voor een online versie van het spel pong/arkanoid) dan moest de vorige instantie perse afgesloten zijn, anders kregen we allemaal excepties en errors waar we niets mee konden. Dus als antwoord daarvoor hebben we alle verwijzingen van en naar de thread dus op null gezet, alvorens eerst alle streams en sockets te sluiten en de thread te stoppen, waarna we de garbage collector hebben aangeroepen om het zaakje af te ronden. Maar dit gaat een beetje offtopic dus ik stop maar ;)

[ Voor 53% gewijzigd door esf op 19-03-2003 18:46 ]

The hardest thing in the world to understand is the income tax. - Albert Einstein


Verwijderd

Je zou die garbage collection niet nodig moeten hebben. Ik heb al heel wat servertjes met ServerSockets gebouwd en ik heb het nooit nodig gehad.
Je mag er dus ook niet op vertrouwen dat het altijd werkt als je relied op die GC.

Probeer eens een sample programma dat een ServerSocket meerdere malen achter elkaar opent en weer sluit. Dit moet geen problemen opleveren. Ik denk dat alles ervan afhangt dat je wacht totdat de ServerSocket gesloten is voordat je er weer een opent. Als je dat laat doen door een Thread waar je geeneens een referentie meer naar hebt, wordt het wel een beetje gokken wat er allemaal gebeurt....

Als je alleen de ServerSocket closed kan je testen of hij open is als je hem opnieuw wil gaan openen...

Success ermee.
Pagina: 1