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;
}
}
come-on nicht faul sein, nicht nur Dump alle Ihre Code. –
Wrapping 'client.getOutputStream()' in einem PrintWriter und einem DataOutputStream fordert Probleme. Wickeln Sie es in einen einzigen Writer oder OutputStream. – VGR
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