2017-08-30 194 views
1

我正在爲Java中的套接字客戶端編碼。 在程序中,我想從服務器獲取信息。 當服務器收到「GET_LIGHTS」命令時,它將以JSON格式發回數據。永久性套接字客戶端塊

但在我的代碼中,bw.write()bw.flush()socket.close()之前不起作用。 因此,BufferedReader對象沒有準備好:br.ready()返回false。

在我的代碼中是否有任何錯誤?

客戶端代碼如下所示。

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(); 
    } 

} 

編輯:

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); 
    } 



} 

回答

2

如果您的服務器使用readLine(),因爲很可能,它會阻止,直到關閉連接,因爲你不是發送線。

添加bw.newLine()之前的flush()

編輯正如預測的那樣,您的服務器沒有發送線路,所以需要與上述相同的處理。但是有一個問題前:

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

這個循環在服務器不可能退出直到客戶端關閉連接。您應該一次在服務器上處理一條線,否則會降低您對客戶行爲的期望。

+0

謝謝你的回答。 我的服務器正在使用'readLine()'。 正如你所建議的,我試圖插入'bw.newLine()',但情況是一樣的。 – Ryoto

+1

@Ryoto也許你的服務器代碼是錯誤的。你可能不應該在那裏使用'br.ready()'。 – Kayaman

+0

@Ryoto讓我們看看你的服務器代碼。例如,*服務器*發送一行?或者誤用'ready()'? – EJP