Java Lesen und schreiben auf Sockets

PEASANT KING

Commander
Registriert
Okt. 2008
Beiträge
2.412
Moin Leute,

ich programmiere ein Serverplugin für Minecraft Bukkit.
Sinn dieses Plugins ist es mittels Eingaben innerhalb einer Website Befehle an Bukkit zu senden und serverseitige Antworten zu erhalten soweit so gut.

Nun habe ich ein kleines Verständnisproblem:

Wenn ich Socketobjekt erstelle und Verbindungen akzeptiere, kann ich entweder lesen vom Socket oder schreiben auf dem Socket.
Ich verstehe nicht wieso ich beim lesen vom Socket, den Socket anschließend schließen muss, damit mir meine PHP Seite das Ergebnis ausgibt.
Weiteres Problem dadurch ist, dass ich nach dem Schließen des Sockets nichts mehr an Bukkit senden kann, da der Socket ja zu ist.

Hier mal ein kleiner Auschnitt meines Codes:
Code:
public class BukkitCommandServer extends Thread {
    
    boolean socket_active;
    Socket socket;
    Server bukkit;
    String port;
    BukkitCommandResponder response;
    BukkitCommandInterpreter interprete;
    
    
    BukkitCommandServer(Server server, String port) {
        this.bukkit = server;
        this.port = port;
    }

    
    
    @Override
    public void run() {
        socket_active = true;
        
        try {
            ServerSocket server = new ServerSocket(Integer.parseInt(port));
            System.out.println("BCOM: Socket activated on port: "+port);

                while(socket_active) {
                    Socket socket = server.accept();
                    response = new BukkitCommandResponder(socket);  
                    interprete = new BukkitCommandInterpreter(socket); 
                }
                socket.close();
        } catch (IOException ex) {
            Logger.getLogger(BukkitCommandServer.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

Verbundene Klassen habe ich mal ausgelassen. Können aber nachgereicht werden.
 
Das Problem mit dem Schließen vom Socket kommt wohl eher durch dein PHP-Skript.

Desweiteren solltest du die Zeile Socket socket = server.accept(); vor die Schleife setzen. Sämtliche Client-Kommunikation läuft durch den Socket, den du durch server.accept() bekommst. Es wird nicht bei jeder Übertragung ein neuer Socket aufgemacht (bei einer KeepAlive-Verbindung zumindest nicht).
Und damit nicht aktiv in der Schleife auf neue Übertragungen gewartet wird (99% CPU-Last), würde ich da noch ein Thread.sleep(1) (1 ms warten -> 0% CPU-Last) einfügen.
 
Du meinst also ich muss in meinem PHP Skript sagen, das das er die Verbindung schließen soll und erst später wieder aufrufen soll ?
 
Ich kann leider nicht viel helfen, da ich nicht sicher bin ob "BukkitCommandResponder" eine selbstgeschriebene Klasse ist oder nicht. Im Netz war jetzt auf die schnelle auch nichts zu finden.

Ich könnte mir aber vorstellen, dass das so ähnlich wie beim lesen und schreiben von Streams ist. Hast du einen Streamreader/BufferedReader benutzt?
Hier mal ein Beispiel wie das mit Streams funktioniert:

Code:
public String sendenempfangen(String text){
try{
	OutputStream os = client.getOutputStream();
	OutputStreamWriter osw = new OutputStreamWriter(os);
        BufferedWriter bwr = new BufferedWriter(osw);
	InputStream is = client.getInputStream();
	InputStreamReader isr = new InputStreamReader(is);
	BufferedReader br = new BufferedReader(isr);
	bwr.write(text);
        bwr.newLine();
        bwr.flush();
        System.out.println("vor empfangen");
        String temp = br.readLine();
        System.out.println("1"+temp);
        return temp;
}
	//br.close();
	catch(UnknownHostException uhe) { System.out.println(uhe); }
	catch(IOException ioe) { System.out.println(ioe); }
        
return "Fehler";
}
 
Nein, ich meine, dass das PHP-Skript daran Schuld hat, dass du nach dem Lesen des Sockets ihn schließen musst, damit was auf deiner Seite angezeigt wird. Das sollte normal nicht der Fall sein.

Das PHP-Skript sollte eigentlich den Socket lesen und dann weiter machen bei was-auch-immer. Das tut es aber offenbar nicht. Und daran sind die Sockets nicht Schuld.
 
Es handelt sich alles um selbst geschriebenes @FlyingEagle.

Klasse zur Ausgabe in PHP
Code:
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package gfm.ll.bcom;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author LL
 */
public class BukkitCommandResponder {
    
   public BukkitCommandResponder(Socket socket) {

        BufferedWriter output = null;
        
        try {
            output = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            output.write("Hello World!");
            output.close();
        } catch (IOException ex) {
            Logger.getLogger(BukkitCommandInterpreter.class.getName()).log(Level.SEVERE, null, ex);
        }  
    }
}

Klasse zum einlesen in Bukkit
Code:
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package gfm.ll.bcom;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author LL
 */
public class BukkitCommandInterpreter {

    BukkitCommandInterpreter(Socket socket) {
        BufferedReader input = null;
        try {
            input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
           
            StringBuilder interprete = new StringBuilder(); 
            String line = null;
                
            while ((line = input.readLine()) != null) {
                interprete.append(line);  
                System.out.println("BCOM: "+interprete);
            }
            input.close();
        } catch (IOException ex) {
            Logger.getLogger(BukkitCommandInterpreter.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
PHP:
<?php    

    $PORT = 25568;
    $HOST = "localhost";
    
    $msg = $_GET["command"];
    
    $sock = socket_create(AF_INET, SOCK_STREAM, 0) //TCP/IP SOCKET ERSTELLEN
    or die("error: could not create socket\n");
    
    $conn = socket_connect($sock, $HOST, $PORT) //MIT DEM SERVER VERBINDEN ÜBER ZUVOR ERSTELLTEM SOCKET
    or die("error: could not connect to host\n");

    
    
    
    $write = socket_write($sock, $msg);
    echo $write;
    
    $read = socket_read ($sock, "12", PHP_NORMAL_READ);    //FÜR SPÄTERE IMPLEMENTIERUNGEN, UM SERVER INFOS ABZUGREIFEN
        echo $read;
    
?>
 
Ich glaube hier ist der Fehler:
Code:
while ((line = input.readLine()) != null) {
                interprete.append(line);  
                System.out.println("BCOM: "+interprete);
            }

Wenn die Schleife das erste mal durchgelaufen ist und nichts auf dem Stream ansteht, dann hört die Schleife auf. Das ist aber nicht das was du willst. Das Teil soll ja solange laufen bis du das Programm beendest

Versuche mal:
Code:
while (true) {
  if (line = input.readLine()) == null)  
    break;
  else{
    interprete.append(line);  
    System.out.println("BCOM: "+interprete);
  }
}

Und wenn du Daten auf deinen BufferedWriter schreibst vergiss ein output.flush() nicht. Damit wird dann der gepufferte Datenstrom auch wirklich geschrieben. Sonst kann etwas gesendet werden, muss aber nicht.
 
@FlyingEagle: Dein Code macht doch genau das Selbe wie der von DJ_We$t, oder?
Du müsstest das break durch ein continue ersetzen, damit er in der Schleife bleibt.

Ich denke aber nicht, dass das gewünscht ist, denn wenn keine Daten zum Lesen da sind blockiert die Methode einfach. Sie würde nur null liefern (oder eine Exception werfen) wenn die Verbindung beendet wird, d.h. du hast eine Endlosschleife.
 
Das close(); flushed den Stream sowieso vorher bevor es den Stream closed.
Und die Ausgabe wenn ich per PHP was an den Stream sende funktioniert auch dauerhaft!
So ist es ja auch von mir gewünscht.

Was nicht funktioniert ist das senden vom Server an PHP.
 
Zurück
Oben