2016-06-16 13 views
-1

Ich habe einen Multi-Client-TCP-Server geschrieben, der den doppelten Zweck hat, Json (textbasierte) Befehlszeichenfolgen zu senden und eine SQLite-Datenbankdatei an mehrere Clients zu senden. Alles funktioniert gut, außer ... die Datenbankdatei verwendet das spezielle Zeichen hex81 (dezimal 129) für einige interne Zwecke. Wenn ich die Datenbankdatei in ein Bytearray lese, konvertiert Java dieses Zeichen in dezimal -127, da Java eine vorzeichenbehaftete Darstellung von Bytes hat. Allerdings überträgt der Socket dieses Zeichen tatsächlich als hex3F. Wenn ich also die Daten im Client speichern und in einer Datei speichern lasse, ist die Datenbank aufgrund des Vorhandenseins von h3F-Zeichen anstelle von h81 beschädigt.Senden einer Binärdatei über einen Java-Socket

Warum passiert das und wie korrigiere ich es? Hier

ist der vollständige Code, die ich verwende für den Server (eine neue Instanz dieser Klasse gestartet wird durch eine separate TCPServer Klasse, wenn ein Client eine Verbindung):

public class TCPServerThread extends Thread { 

// Connect status constants 
private final static int NULL = 0; 
private final static int DISCONNECTED = 1; 
private final static int DISCONNECTING = 2; 
private final static int BEGIN_CONNECT = 3; 
private final static int CONNECTED = 4; 

private final static String END_SESSION = new Character((char)0).toString(); // Indicates the end of a session 

// Connection state info 
private int connectionStatus = DISCONNECTED; 

private static StringBuffer txBuffer = new StringBuffer(""); 
private static ByteArrayOutputStream txBuffer2 = new ByteArrayOutputStream(); 

private static File file; 

// TCP Components 
private ServerSocket serverSocket = null; 
private Socket clientSocket = null; 
private BufferedReader in = null; 
private PrintWriter out = null; 
private DataOutputStream out2 = null; 
private String s = ""; 

private DecodeJson dj = new DecodeJson(); 
private boolean doRun; 


public TCPServerThread(Socket socket) throws IOException { 

    doRun = true; 
    clientSocket = socket;  
    changeStatusTS(BEGIN_CONNECT, true); 

} 

public void run() { 

    while (doRun) { 
     try { // run every ~10 ms 
      Thread.sleep(10); 
     } 
     catch (InterruptedException e) {} 

     if (Mainscreen.shutdown == true || TCPClient.close == true) 
      connectionStatus = DISCONNECTING; 

     switch (connectionStatus) { 

      case BEGIN_CONNECT: 

       try { 
        in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); 
        out = new PrintWriter(clientSocket.getOutputStream(), true); 
        out2 = new DataOutputStream(clientSocket.getOutputStream()); 
        TCPServer.writers.add(out);    // add this socket to the connected clients list 
        changeStatusTS(CONNECTED, true); 
       } 
       // If error, clean up and output an error message 
       catch (IOException e) { 
        cleanUp(); 
        changeStatusTS(DISCONNECTED, false); 
       } 
       break; 

      case CONNECTED: 

       try { 
        // Send data 
        if (txBuffer.length() != 0) { 
         for (PrintWriter writer : TCPServer.writers) { 
          writer.print(txBuffer); 
          writer.flush(); 

          if(writer.checkError()) { 
          closeSocket(); 
          changeStatusTS(DISCONNECTING, true); 

          }else { 
           changeStatusTS(NULL, true); 
          } 
         } 
         txBuffer.setLength(0); 
        } 

        if (txBuffer2.size() != 0) { 
         byte[] result = txBuffer2.toByteArray(); 
         System.out.println(result[745] + "," + result[746] + "," + result[747] + "," + result[748] + "," + result[749] + "," + result[750]); 
         out2.write(result); 
         out2.flush();       
         txBuffer2.reset(); 
        } 

        // Receive data 
        if (in.ready()) { 
         s = in.readLine(); 
         if ((s != null) && (s.length() != 0)) { 
          // Check if it is the end of a transmission 
          if (s.equals(END_SESSION)) { 
           changeStatusTS(DISCONNECTING, true); 
          } 
          // Otherwise, receive text 
          else {         
           dj.receiveString(s); 
           changeStatusTS(NULL, true); 
          } 
         } 
        } 
       } 
       catch (IOException e) { 
        System.out.println("Socket error " + e); 
        cleanUp(); 
        changeStatusTS(DISCONNECTED, false); 
       } 
       break; 

      case DISCONNECTING: 

       // Tell clients to disconnect as well 
       if (out != null) { 
        out.print(END_SESSION); 
        out.flush(); 
       } 
       // Clean up (close all streams/sockets) 
       cleanUp(); 
       changeStatusTS(DISCONNECTED, true); 
       break; 

      default: break; 
     } 
    } 
} 

// Add command to text send-buffer 
public static void sendString(String s) { 

    synchronized (txBuffer) { 
     txBuffer.append(s + "\n"); 
    } 
} 

// Add file data to binary send buffer 
public static void sendFile(String filename) { 

    synchronized (txBuffer2) { 
     file = new File(filename);      
     byte[] content = new byte[(int)file.length()]; 
     FileInputStream fin; 
     try { 
      fin = new FileInputStream(file);    
      fin.read(content); 
      System.out.println(content[745] + "," + content[746] + "," +content[747] + "," +content[748] + "," + content[749] + "," + content[750]); 
      txBuffer2.write(content);  
      fin.close(); 
     } catch (FileNotFoundException e) { 
      e.printStackTrace(); 
     } catch (IOException f) { 
      f.printStackTrace(); 
     } 
    } 

} 

private void changeStatusTS(int newConnectStatus, boolean noError) { 

    // Change state if valid state 
    if (newConnectStatus != NULL) { 
     connectionStatus = newConnectStatus; 
    } 

} 

private void closeSocket(){ 
    try { 
     if (clientSocket != null) { 
      clientSocket.close(); 
      clientSocket = null; 
     } 
    } 
    catch (IOException e) { clientSocket = null; } 

} 

// Cleanup for disconnect 
private void cleanUp() { 
    try { 
     if (serverSocket != null) { 
      serverSocket.close(); 
      serverSocket = null; 
     } 
    } 
    catch (IOException e) { serverSocket = null; } 

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

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

    if (out != null) { 
     TCPServer.writers.remove(out);   // remove this socket for the connected sockets list 
     out.close(); 
     out = null; 
    } 
    doRun = false; 

} 

}

+0

come-on nicht faul sein, nicht nur Dump alle Ihre Code. –

+1

Wrapping 'client.getOutputStream()' in einem PrintWriter und einem DataOutputStream fordert Probleme. Wickeln Sie es in einen einzigen Writer oder OutputStream. – VGR

+0

Sie können 'Reader' und' Writers' nicht verwenden, wenn Binärdaten vorhanden sind. Sie werden mit ziemlicher Sicherheit alles neu überdenken müssen. Ich würde separate Sockets für den Text und die Datenbank verwenden. – EJP

Antwort

-1

So wie EJP vorgeschlagen, das Problem liegt an der Verwendung von Lesern und Schreibern. Der folgende Code funktioniert jetzt wie erwartet (Danke für den Tipp EJP). Ich werde mich damit beschäftigen, das von VGR aufgeworfene Problem anzusprechen, client.getOutputStream() sowohl in einem PrintWriter als auch in einem BufferedOutputStream zu verpacken, aber für den Moment funktioniert der Code gut (dies ist ein laufender Prozess).

public class TCPServerThread extends Thread { 

// Connect status constants 
private final static int NULL = 0; 
private final static int DISCONNECTED = 1; 
private final static int DISCONNECTING = 2; 
private final static int BEGIN_CONNECT = 3; 
private final static int CONNECTED = 4; 

private final static String END_SESSION = new Character((char)0).toString(); // Indicates the end of a session 

// Connection state info 
private int connectionStatus = DISCONNECTED; 

private static StringBuffer txBuffer = new StringBuffer(""); 
private static BufferedOutputStream out2 = null; 

private static File file; 

// TCP Components 
private ServerSocket serverSocket = null; 
private Socket clientSocket = null; 
private BufferedReader in = null; 
private PrintWriter out = null; 
private static BufferedInputStream fileData = null; 
private String s = ""; 

private DecodeJson dj = new DecodeJson(); 
private boolean doRun; 


public TCPServerThread(Socket socket) throws IOException { 

    doRun = true; 
    clientSocket = socket;  
    changeStatusTS(BEGIN_CONNECT, true); 

} 

public void run() { 

    while (doRun) { 
     try { // run every ~10 ms 
      Thread.sleep(10); 
     } 
     catch (InterruptedException e) {} 

     if (Mainscreen.shutdown == true || TCPClient.close == true) 
      connectionStatus = DISCONNECTING; 

     switch (connectionStatus) { 

      case BEGIN_CONNECT: 

       try { 
        in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); 
        out = new PrintWriter(clientSocket.getOutputStream(), true); 
        out2 = new BufferedOutputStream(clientSocket.getOutputStream()); 

        TCPServer.writers.add(out);    // add this socket to the connected clients list 
        changeStatusTS(CONNECTED, true); 
       } 
       // If error, clean up and output an error message 
       catch (IOException e) { 
        cleanUp(); 
        changeStatusTS(DISCONNECTED, false); 
       } 
       break; 

      case CONNECTED: 

       try { 
        // Send data 
        if (txBuffer.length() != 0) { 
         for (PrintWriter writer : TCPServer.writers) { 
          writer.print(txBuffer); 
          writer.flush(); 

          if(writer.checkError()) { 
          closeSocket(); 
          changeStatusTS(DISCONNECTING, true); 

          }else { 
           changeStatusTS(NULL, true); 
          } 
         } 
         txBuffer.setLength(0); 
        } 

        if (fileData != null) { 
         byte[] buffer = new byte[(int) file.length()]; 
         for (int read = fileData.read(buffer); read >=0; read = fileData.read(buffer)) out2.write(buffer, 0, read); 
         out2.flush(); 
         fileData = null; 
        } 

        // Receive data 
        if (in.ready()) { 
         s = in.readLine(); 
         if ((s != null) && (s.length() != 0)) { 
          // Check if it is the end of a transmission 
          if (s.equals(END_SESSION)) { 
           changeStatusTS(DISCONNECTING, true); 
          } 
          // Otherwise, receive text 
          else {         
           dj.receiveString(s); 
           changeStatusTS(NULL, true); 
          } 
         } 
        } 
       } 
       catch (IOException e) { 
        System.out.println("Socket error " + e); 
        cleanUp(); 
        changeStatusTS(DISCONNECTED, false); 
       } 
       break; 

      case DISCONNECTING: 

       // Tell clients to disconnect as well 
       if (out != null) { 
        out.print(END_SESSION); 
        out.flush(); 
       } 
       // Clean up (close all streams/sockets) 
       cleanUp(); 
       changeStatusTS(DISCONNECTED, true); 
       break; 

      default: break; 
     } 
    } 
} 

// Add command to text send-buffer 
public static void sendString(String s) { 

    synchronized (txBuffer) { 
     txBuffer.append(s + "\n"); 
    } 
} 

// Add file data to binary send buffer 
public static void sendFile(String filename) { 

    file = new File(filename);      
    try { 
     fileData = new BufferedInputStream(new FileInputStream(file)); 
    } catch (FileNotFoundException e) { 
     e.printStackTrace(); 
    } 

} 

private void changeStatusTS(int newConnectStatus, boolean noError) { 

    // Change state if valid state 
    if (newConnectStatus != NULL) { 
     connectionStatus = newConnectStatus; 
    } 

} 

private void closeSocket(){ 
    try { 
     if (clientSocket != null) { 
      clientSocket.close(); 
      clientSocket = null; 
     } 
    } 
    catch (IOException e) { clientSocket = null; } 

} 

// Cleanup for disconnect 
private void cleanUp() { 
    try { 
     if (serverSocket != null) { 
      serverSocket.close(); 
      serverSocket = null; 
     } 
    } 
    catch (IOException e) { serverSocket = null; } 

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

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

    if (out != null) { 
     TCPServer.writers.remove(out);   // remove this socket for the connected sockets list 
     out.close(); 
     out = null; 
    } 
    doRun = false; 

} 

}

+0

Es macht mir zu schaffen, dass die Verwendung von Readers and Writers die geringste Notiz von allem darstellt, was ich hier gesagt habe, dass ich sie nicht verwende. – EJP

+0

Sie haben vorgeschlagen, sie nicht für Binärdaten zu verwenden. Ich benutze jetzt nur Streams für Binärdateien, die das Problem gelöst haben. Allerdings benutze ich immer noch Leser und Schreiber für die Textübertragung, was die Standardmethode dafür zu sein scheint. Also, was ist dein Problem genau? – Razza