2017-08-30 3 views
1

Ich codiere Socket-Client in Java. In dem Programm möchte ich Informationen vom Server abrufen. Wenn der Server den Befehl "GET_LIGHTS" empfängt, sendet er Daten im JSON-Format zurück.Socket-Client blockiert für immer

Aber in meinem Code, und bw.flush() funktioniert nicht vor socket.close(). So ist das BufferedReader-Objekt nicht bereit: br.ready() gibt false zurück.

Gibt es einen Fehler in meinem Code?

Der Client-Code wird unten angezeigt.

package monitor; 

import java.io.*; 
import java.net.InetSocketAddress; 
import java.net.Socket; 
import java.util.ArrayList; 

public class SocketClient { 
    static private int port; 
    static private String hostName; 
    private Socket socket; 

    public SocketClient(String host, int port) { 
     this.hostName = host; 
     this.port = port; 
    } 

    // get lights by JSON 
    public void getLights() { 
     try { 
      // generate socket 
      InetSocketAddress endpoint = new InetSocketAddress(hostName, port); 
      socket = new Socket(); 
      socket.connect(endpoint); 

      // setting 
      OutputStreamWriter out = new OutputStreamWriter(socket.getOutputStream()); 
      BufferedWriter bw = new BufferedWriter(out); 

      InputStreamReader in = new InputStreamReader(socket.getInputStream()); 
      BufferedReader br = new BufferedReader(in); 

      // send command 
      bw.write("GET_LIGHTS"); 
      bw.flush(); 

      // receive message from server 
      System.out.println(br.readLine()); 

      socket.close(); 

     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

    public void initLights(ArrayList<Light> lights) { 
     getLights(); 
    } 

} 

Edited:

import com.fasterxml.jackson.core.JsonProcessingException; 
import com.fasterxml.jackson.databind.ObjectMapper; 

import java.io.*; 
import java.net.ServerSocket; 
import java.net.Socket; 
import java.util.ArrayList; 

public class SocketServer extends Thread{ 
    static final int PORT = 44344; 
    static private ILS ils; 
    private ServerSocket serverSocket; 
    private Socket socket; 

    public SocketServer(ILS ils) { 
     this.ils = ils; 
    } 
    @Override 
    public void run() { 
     serverSocket = null; 
     System.out.println("Server: listening"); 

     try { 
      serverSocket = new ServerSocket(PORT); 
      while(true){ 
       socket = serverSocket.accept(); 

       BufferedReader br = new BufferedReader(
         new InputStreamReader(socket.getInputStream())); 
       ArrayList<String> cmd = new ArrayList<>(); 
       String in; 
       while((in = br.readLine()) != null){ 
        cmd.add(in); 
       } 
       command(cmd); 
       if(socket != null){ 
        socket.close(); 
       } 
      } 

     } catch (IOException e) { 
      e.printStackTrace(); 
     } 

     if(serverSocket != null){ 
      try { 
       serverSocket.close(); 
       serverSocket = null; 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

    // send message to client 
    private void sendMessage(String str) { 
     System.out.println(str); 
     try { 
      OutputStream output = socket.getOutputStream(); 
      BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(output)); 
      bw.write(str + "¥n"); 
      bw.flush(); 
      bw.close(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

    // error 
    private void printError(String err) { 
     String str = "ERROR; "; 
     str += err; 
     sendMessage(str); 
    } 

    public void command(ArrayList<String> cmd) { 
     String mode = cmd.get(0); 
     if(mode == null){ 

     }else switch(mode){ 
      case "MANUAL_SIG-ALL": 
       System.out.println("全照明一括 信号値指定調光"); 
       manualSigAll(cmd.get(1)); 
       break; 
      case "MANUAL_SIG-INDIVIDUAL": 
       System.out.println("全照明独立 信号値指定調光"); 
       manualSigIndividual(cmd.get(1)); 
       break; 
      case "MANUAL_ID-SIG": 
       System.out.println("照明ID・信号値指定調光"); 
       manualIDSig(cmd.get(1)); 
       break; 
      case "MANUAL_ID-RELATIVE": 
       System.out.println("照明ID・相対信号値指定調光"); 
       break; 
      case "DOWNLIGHT_ALL": 
       System.out.println("Downlight: All Control"); 
       downlightAll(cmd.get(1)); 
       break; 
      case "DOWNLIGHT_INDIVIDUAL": 
       System.out.println("Downlight: Individual control"); 
       downlightIndividual(cmd.get(1)); 
       break; 
      case "GET_LIGHTS": 
       System.out.println("Sending lights via JSON"); 
       sendLights(); 
       break; 
      default: 
       System.out.println("Error: 不明なmode command"); 
     } 
    } 

    // 全照明一括 信号値指定調光 
    private void manualSigAll(String sigs) { 
     if(sigs == null) { 
      System.out.println("信号値のフォーマットを確認してください"); 
     } else { 
      ArrayList<Integer> s = new ArrayList<>(); 
      String[] buf = sigs.split(","); 
      for(String i:buf) s.add(Integer.parseInt(i)); 
      for(Light l: ils.getLights()) { 
       l.setLumPct((double)s.get(0)/255.0*100.0); 
       l.setSignal(s.get(0), s.get(1)); 
      } 
     } 
     // 調光 
     ils.downlightDimmer.send(); 

    } 

    // 全照明独立 信号値指定調光 
    private void manualSigIndividual(String sigs) { 
     if(sigs == null) { 
      System.out.println("信号値のフォーマットを確認してください"); 
     } else { 
      ArrayList<Integer> s = new ArrayList<>(); 
      String[] buf = sigs.split(","); 
      for(String i:buf) s.add(Integer.parseInt(i)); 
      for(int i=0; i<ils.getLights().size(); i++) { 
       ils.getLights().get(i).setSignal(s.get(0), s.get(1)); 
       s.remove(0); 
       s.remove(0); 
      } 
     } 
     ils.downlightDimmer.send(); 
    } 

    // 照明ID・信号値指定調光 
    private void manualIDSig(String sigs) { 
     if(sigs == null) { 
      System.out.println("信号値のフォーマットを確認してください"); 
     } else { 
      ArrayList<Integer> s = new ArrayList<>(); 
      String[] buf = sigs.split(","); 
      for(String i:buf) s.add(Integer.parseInt(i)); 
      System.out.println(s.get(0)); 
      ils.getLight(s.get(0)).setSignal(s.get(1), s.get(2)); 
     } 
     ils.downlightDimmer.send(); 
    } 

    private void downlightAll(String cmd) { 
     if(cmd == null) { 
      printError("Check for data command."); 
     } else { 
      ArrayList<Double> data = new ArrayList<>(); 
      String[] buf = cmd.split(","); 
      for(String i:buf) data.add(Double.parseDouble(i)); 
      for(Light l: ils.getLights()) { 
       l.setLumPct(data.get(0)); 
       l.setTemperature(data.get(1)); 
      } 
     } 
     // dimming 
     ils.downlightDimmer.send(); 
    } 

    private void downlightIndividual(String cmd) { 
     if(cmd == null) { 
      printError("Check for data command."); 
     } else { 
      ArrayList<Integer> id = new ArrayList<>(); 
      ArrayList<Double> lumPct = new ArrayList<>(); 
      ArrayList<Integer> temp = new ArrayList<>(); 

      String[] buf = cmd.split(","); 
      if(buf.length % 3 != 0) {printError("invalid number of data.");} 

      for(int i=0; i<buf.length/3; i++) { 
       int n = i*3; 
       try { 
        id.add(Integer.parseInt(buf[n])); 
        lumPct.add(Double.parseDouble(buf[n + 1])); 
        temp.add(Integer.parseInt(buf[n + 2])); 
       } catch (Exception e) { 
        printError(e.getMessage()); 
        return; 
       } 
      } 

      while (id.size() > 0) { 
       // update light object 
       Light light = ils.getLight(id.get(0)); 
       light.setLumPct(lumPct.get(0)); 
       light.setTemperature(temp.get(0)); 

       // remove data from array list 
       id.remove(0); 
       lumPct.remove(0); 
       temp.remove(0); 
      } 

      // dimming 
      ils.downlightDimmer.send(); 

     } 
    } 

    private void sendLights() { 
     ObjectMapper mapper = new ObjectMapper(); 
     String json = ""; 
     try { 
      json = mapper.writeValueAsString(ils.getLights()); 
     } catch (JsonProcessingException e) { 
      e.printStackTrace(); 
     } 

     // output 
     sendMessage(json); 
    } 



} 

Antwort

2

Wenn Ihr Server readLine() verwendet, wie es wahrscheinlich ist, wird es blockiert, bis Sie die Verbindung zu schließen, weil Sie nicht Senden eine Linie sind.

Fügen Sie bw.newLine() vor der flush() hinzu.

BEARBEITEN Wie vorhergesagt, sendet Ihr Server keine Leitungen, daher muss dieselbe Behandlung wie oben beschrieben durchgeführt werden. Jedoch gibt es ein Problem, anteriore:

while((in = br.readLine()) != null){ 
    cmd.add(in); 
} 

Diese Schleife in dem Server kann unmöglich verlassen, bis der Client die Verbindung geschlossen wird. Sie sollten eine Zeile auf einmal im Server verarbeiten oder Ihre Erwartungen an das Verhalten des Clients moderieren.

+0

Vielen Dank für Ihre Antwort. Mein Server benutzt 'readLine()'. Wie Sie vorgeschlagen haben, habe ich versucht, 'bw.newLine()' einzufügen, aber die Situation war die gleiche. – Ryoto

+1

@Ryoto Vielleicht ist der Servercode falsch. Sie sollten wahrscheinlich nicht 'br.ready()' für irgendetwas dort verwenden. – Kayaman

+0

@Ryoto Zeigen Sie uns Ihren Servercode. Sendet der * Server * beispielsweise eine Leitung? Oder missbrauchen 'ready()'? – EJP

Verwandte Themen