• Es freut uns dass du in unser Minecraft Forum gefunden hast. Hier kannst du mit über 130.000 Minecraft Fans über Minecraft diskutieren, Fragen stellen und anderen helfen. In diesem Minecraft Forum kannst du auch nach Teammitgliedern, Administratoren, Moderatoren , Supporter oder Sponsoren suchen. Gerne kannst du im Offtopic Bereich unseres Minecraft Forums auch über nicht Minecraft spezifische Themen reden. Wir hoffen dir gefällt es in unserem Minecraft Forum!

Java Socket

Y

yoshicrafter

Guest
Hallo,
ich arbeite an einem Server und einem Client.
Dies soll erstmal so funktionieren, das wenn sich ein Client verbindet, sagt der Server Willkommen und dann sagt der Server immer wieder, wenn der Client etwas sagt, sagt der Server Du schreibst: Nachricht.
Server Code:
Main.java:
Code:
package server;

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

public class Main {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        try {
            ServerSocket server = new ServerSocket(1234);
            while(true) {
                Socket socket = server.accept();
                new Connection(socket);
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}
Connection.java
Code:
package server;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

public class Connection {

    public Connection(Socket socket) {
        // TODO Auto-generated constructor stub
        try {
            PrintWriter out = new PrintWriter(socket.getOutputStream());
            Scanner in = new Scanner(socket.getInputStream());
            out.println("Willkommen!" + "\n");
            while(true) {
                out.println("Du schreibst: " + in.nextLine() + "\n");
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}
Client Code:
Main.java:
Code:
package client;

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

public class Main {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        try {
            Socket socket = new Socket("127.0.0.1", 1234);
            new Write(socket);
            new Read(socket);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}
Write.java
Code:
package client;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

public class Write {

    public Write(Socket socket) {
        // TODO Auto-generated constructor stub
            try {
                PrintWriter out = new PrintWriter(socket.getOutputStream());
                while(true) {
                    out.println(new Scanner(System.in).nextLine() + "\n");
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    }

}
Read.java
Code:
package client;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

public class Read {

    public Read(Socket socket) {
        // TODO Auto-generated constructor stub
        try {
            Scanner in = new Scanner(socket.getInputStream());
            while(true) {
                System.out.println("Antwort von Server: " + in.nextLine());
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}
und das problem ist, wenn ich den client starte, verbindet der sich zwar zum server, aber da kommt vom server keine reaktion, auch nicht, wenn ich was eingebe, also zum server schicke
 

UnityGaming

Workaholic
Registriert
25 Oktober 2015
Beiträge
527
Alter
26
Diamanten
312
Minecraft
FastFelix771
Was davon funktioniert denn überhaupt bzw. tut es nicht?
Übrigens: Du hast überall while (true) Schleifen... diese blockieren den Thread in dem sie ausgeführt werden.

Du wirst also vermutlich max. 1 Verbindung gleichzeitig abhandeln können. (wenn überhaupt)

Du wirst für einzelne Verbindungen separate Threads benötigen, sonst wird das nichts.
Oder du nimmst die Channel (NIO) API zur Hand - damit kannst du das ganze Non-Blocking und mit weitaus weniger Threads gestalten.

Hier ein kleines Tutorial darüber:
https://examples.javacodegeeks.com/core-java/nio/java-nio-socket-example/

Ich hoffe das bringt dich ein wenig weiter.
Den Vorschlag oben mit den separaten Threads solltest du übrigens nicht hernehmen... Minecraft hat damals fast das Gleiche getan, bis wir dann endlich, dank dem Netty Framework, von dieser Qual erlöst wurden und schlagartig Server mit 100+ Spielern laggfrei möglich waren.

Netty ist übrigens auch nicht so schwer, wenn man sich damit befasst - nimmt einem 90% der Arbeit ab und leistet nen großartigen Job!
Aber für ein so kleines Beispiel wäre das eher übertrieben, außerdem tut es zu Lernzwecken auch gut, wenn man mal selbst sich den Problemen stellt, die Frameworks wie Netty schon seit Jahren gelöst haben - einfach um mal ein Bild davon zu kriegen was man denn alles machen bzw. falsch machen kann.
 

IDK_WHO_AM_I

Kuhfänger
Registriert
30 Mai 2017
Beiträge
66
Alter
28
Diamanten
300
Minecraft
IDK_WHO_AM_I
Hier mal ein paar Klassen aus meinem McPermission
Javascript:
package de.zm4xi.mcp.plugincom.serverutils;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;

import de.zm4xi.mcp.bungee.main.McBungeeCord;

public class ServerThread extends Thread {

    private Socket socket;
    private InputStream in;
    private OutputStream out;
    private BufferedReader reader;
    private PrintWriter writer;

    public ServerThread(Socket socket) {
        this.socket = socket;
    }

    @SuppressWarnings("deprecation")
    @Override
    public void run() {
        try {
            in = socket.getInputStream();
            out = socket.getOutputStream();
       
            reader = new BufferedReader(new InputStreamReader(in));
            writer = new PrintWriter(out);
       
            String message = null;
            while ((message = reader.readLine()) != null) {
                String[] array = message.split(" ");
                if (array[0].equalsIgnoreCase("DISCONNECT")) {
                    McBungeeCord.getInstance().getServer().getThreads().remove(this);
                    this.destroy();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public InputStream getIn() {
        return in;
    }

    public OutputStream getOut() {
        return out;
    }

    public BufferedReader getReader() {
        return reader;
    }

    public PrintWriter getWriter() {
        return writer;
    }

    public void sendMessage(String message) {
        writer.write(message + "\n");
        writer.flush();
    }

}

Javascript:
package de.zm4xi.mcp.plugincom;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.sql.SQLException;

import de.zm4xi.mcp.spigot.main.McSpigot;

public class Client extends Thread {

    private Socket socket;

    private InputStream in;
    private OutputStream out;
    private BufferedReader reader;
    private PrintWriter writer;

    @Override
    public void run() {
        try {
            socket = new Socket(McSpigot.getInstance().getConnFile().getString("serverip"), McSpigot.getInstance().getConnFile().getInt("serverport"));
            in = socket.getInputStream();
            out = socket.getOutputStream();
            reader = new BufferedReader(new InputStreamReader(in));
            writer = new PrintWriter(out);
       
            String message = null;
            while ((message = reader.readLine()) != null) {
                String[] array = message.split(" ");
                if (array[0].equalsIgnoreCase("UPDATE")) {
                    System.out.println("[MCP] Reloading groups");
                    try {
                        McSpigot.getInstance().getGroupManager().loadGroups();
                        McSpigot.getInstance().getUserManager().loadUsers();
                        McSpigot.getInstance().getUserManager().loadUserGroups();
                        McSpigot.getInstance().refreshPermissions();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                    System.out.println("[MCP] Groups reloaded");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public InputStream getIn() {
        return in;
    }

    public OutputStream getOut() {
        return out;
    }

    public BufferedReader getReader() {
        return reader;
    }

    public PrintWriter getWriter() {
        return writer;
    }

    public void sendMessage(String message) {
        writer.write(message + "\n");
        writer.flush();
    }

}

Javascript:
package de.zm4xi.mcp.plugincom;

import java.net.ServerSocket;
import java.net.Socket;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import de.zm4xi.mcp.bungee.main.McBungeeCord;
import de.zm4xi.mcp.plugincom.serverutils.ServerThread;

public class Server extends Thread {

    private List<ServerThread> threads;

    @SuppressWarnings("resource")
    @Override
    public void run() {
        try {
            threads = new ArrayList<ServerThread>();
            ServerSocket server;
            server = new ServerSocket(5555);
            while (true) {
                Socket socket = server.accept();
                ServerThread tr = new ServerThread(socket);
                tr.start();
                getThreads().add(tr);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void sendUpdateMessage() {
        for (ServerThread trds : getThreads()) {
            trds.sendMessage("UPDATE");
        }
        try {
            McBungeeCord.getInstance().getGroupManager().loadGroups();
            McBungeeCord.getInstance().getUserManager().loadUsers();
            McBungeeCord.getInstance().getUserManager().loadUserGroups();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public List<ServerThread> getThreads() {
        return threads;
    }

}

Selbstverständlich musst du dir meine Plugin spezifischen Klassen wegdenken xD
Aber der Code funktioniert so :D

@UnityGaming hat recht wenn du es nicht über einen neuen Thread löst wird der Main Server Thread blockiert!

Im ServerThread kannst du Nachrichten von Clients abfangen und bearbeiten und der Client selbst empfängt die Nachrichten vom Server
 

UnityGaming

Workaholic
Registriert
25 Oktober 2015
Beiträge
527
Alter
26
Diamanten
312
Minecraft
FastFelix771
Aber der Code funktioniert so :D
Sieht soweit ganz ok aus, aber... sofern ich das jetzt nicht übersehen habe:

  • catch (Exception e) {
  • e.printStackTrace();
  • }
Du wirfst bloß eine Exception, schließt aber nicht die genutzten Ressourcen irgendwo, also die In- und Output Streams.
Versuch mal deinen Try-Catch Block in ein Try-With-Resources umzubauen, dann hast du dort eine Sorge weniger.
 

IDK_WHO_AM_I

Kuhfänger
Registriert
30 Mai 2017
Beiträge
66
Alter
28
Diamanten
300
Minecraft
IDK_WHO_AM_I
? wieso sollte ich. Das habe ich selbstverständlich im onDisable und an paar andern Parts gemacht xD

Das ist ein funktionierendes Plugin das es bereits gibt xD
McPermission

Meiner Meinung nach sollte das so gehen :D Aber cool das du es gesehen ahst das es nicht da drinne steht :D
 

IDK_WHO_AM_I

Kuhfänger
Registriert
30 Mai 2017
Beiträge
66
Alter
28
Diamanten
300
Minecraft
IDK_WHO_AM_I
Das geht automatisch wenn du in deiner Main Klasse
Code:
Server server = new Server();
server.start();

machst :D
wenn du meine Klassen ca so benutzt

Optional:
Code:
        new Thread() {
            @Override
            public void run() {
                // TODO Auto-generated method stub
                
            }
        }.start();
 

UnityGaming

Workaholic
Registriert
25 Oktober 2015
Beiträge
527
Alter
26
Diamanten
312
Minecraft
FastFelix771
Das habe ich selbstverständlich im onDisable und an paar andern Parts gemacht xD
Im onDisable o_O
Also ich gehe davon aus, dass Thread.destroy() ebenfalls die Ressourcen freigibt, aber so wie ich das sehe behandelst du keinen Ausnahmefall.
Als Beispiel:
  • String[] array = message.split(" ");
  • if (array[0].equalsIgnoreCase("DISCONNECT")) {
  • McBungeeCord.getInstance().getServer().getThreads().remove(this);
  • this.destroy();
  • }
  • }
  • } catch (Exception e) {
  • e.printStackTrace();
  • }
Sagen wir mal, dass das die gelesene Zeile leer ist.
Du hast also auch ein leeres String Array.

array[0] => ArrayIndexOutOfBound***ception => Catch Block wird aktiviert, Thread.destroy() wird übergangen und Ressourcen Streams bleiben offen.

pseudo:
Javascript:
try (Socket socket = this.socket) {
  bal bla bla
} catch (Exception iwas) {
bla bla bla
}

Dem try-with-resources ist es egal, ob der Try oder der Catch Block durchläuft, nachdem eins davon beendet ist, werden die verwalteten Ressourcen garantiert und automatisch geschlossen.

Im Worst-Case, also irgendeiner absolut unerwarteten Fehlererscheinung hast du absolut keine Probleme damit und alles regelt sich mehr oder weniger von alleine.

Meiner Meinung nach sollte das so gehen :D
Tut's auch bestimmt.
Das fällt auch erst ab einer gewissen (größeren Menge) solcher Vorfälle auf.
Aber ich wollte es bloß anmerken, ist nicht böse gemeint oder so. :D

Der Teufel steckt nur sehr gerne im Detail. :troll:
Mein Meister täte mir deswegen auf die Finger geben^^
 

UnityGaming

Workaholic
Registriert
25 Oktober 2015
Beiträge
527
Alter
26
Diamanten
312
Minecraft
FastFelix771
@zM4xi Eine Frage hätte ich da noch.
Wenn ich das richtig verstehe, dann synchronisierst du mit diesen Sockets die Permissions zwischen Bungee und einzelnen Spigot Servern, aye?
Warum machst du dir solchen Aufwand und nutzt nicht einfach das PluginMessaging System, das in BungeeCord und in Spigot hervorragend implementiert ist und eigentlich genau diesen Aufgabenbereich abdecken soll?
Dann bräuchtest du auch keine Updates alle n Sekunden machen, sondern schickst eine Plugin Message an alle Server, sobald sich die Permissions ändern. Das hat dann zur Folge, dass die Permissions quasi sofort, ohne weitere Verzögerung übernommen werden.

@yoshicrafter
Haste das mit den Threads verstanden, was Maxi geschrieben hat, oder gibt's da noch Probleme?
 

IDK_WHO_AM_I

Kuhfänger
Registriert
30 Mai 2017
Beiträge
66
Alter
28
Diamanten
300
Minecraft
IDK_WHO_AM_I
@UnityGaming Weil das a) 1 miox komplizierter ist (meiner Meinung nach xD) und b) ich sende jedes mal wenn etwas geändert wird eine ServerSocket raus das sich die Clients von der MySQL die neuen Daten holen sollen.

Hast du schonmal ne CustomPluginMessage gesendet ? Da programmiert sich Minecraft in C++ einfacher xD

Außerdem läuft das so über einen extra Thread und beansprucht nicht so viel Ressourcen des BungeeCord.
Kann sein das man das auch über PluginChannel machen kann finde ich aber nicht so gut :D
 

UnityGaming

Workaholic
Registriert
25 Oktober 2015
Beiträge
527
Alter
26
Diamanten
312
Minecraft
FastFelix771
Oben