2013-04-09 8 views
5

Ich habe einen C++ Server und zwei Clients (Ruby und Java). Alles läuft auf einem 64-Bit-Linux-Rechner (Java 1.7.0_17) Der Ruby-Client ist voll funktionsfähig, aber die Java-Version macht Probleme.Java Client und ein C++ Server senden und empfangen über TCP Socket

In Java habe ich versucht, eine Zeichenfolge vom Client an den Server zu senden. Tatsächlich hat der Server die gesamte Zeichenfolge empfangen, aber der Server denkt, dass noch etwas mehr zu empfangen ist.

Der Rubin-Client sieht ein bisschen wie folgt aus:

socket = TCPSocket.open(@options[:host],@options[:port]) 
test = "Hello, World" 
socket.puts test 
socket.shutdown 1 
response = socket.gets 

Alles gut hier arbeitet. Der Ruby-Client sendet eine Zeichenfolge. Der Server empfängt diese Zeichenfolge und sendet eine Antwort.

Die Java-Version wie folgt aussieht:

String ip = "127.0.0.1"; 
int port = 6686; 
java.net.Socket socket = new java.net.Socket(ip,port); 
OutputStreamWriter out = new OutputStreamWriter(socket.getOutputStream()); 
InputStreamReader in = new InputStreamReader(socket.getInputStream()); 

String msg = "Hello, world!"; 

//send 
PrintWriter pw = new PrintWriter(out, true); 
pw.print(msg); 
pw.flush(); 
// I also tried: out.write(msg); out.flush(); nothing changed 

//receive the reply 
BufferedReader br = new BufferedReader(in); 
char[] buffer = new char[300]; 
int count = br.read(buffer, 0, 300); 
String reply = new String(buffer, 0, count); 
System.out.println(reply); 

socket.close(); 

Auf der anderen Seite gibt es einen C++ Server ist:

string receive(int SocketFD) { 
    char buffer[SOCKET_BUFFER_SIZE]; 
    int recv_count; 

    // empty messagestring 
    string message = ""; 

    // empty buffer 
    memset(buffer, 0, sizeof(buffer)); 

    while ((recv_count = recv(SocketFD, buffer, sizeof(buffer) - 1, 0)) > 0) { 
     /*if (recv_count == -1) { 
     cout << "failed." << endl; 
     break; 
     }*/ 
     cout << recv_count << endl; 
     if (ECHO_SOCKETS) cout << "received: " << buffer << endl; 

     message.append(buffer); 
     memset(buffer, 0, sizeof(buffer)); 

     if (ECHO_SOCKETS) cout << "message is now: " << message << endl; 

    } 
    return message; 
} 

Der Server Ausgabe von der Java-Nachricht ist:

13 
received: Hello, world! 
message is now: Hello, world! 

und dann passiert nichts. Das Problem ist, dass:

recv(SocketFD, buffer, sizeof(buffer) - 1, 0) 

in einer Endlosschleife gefangen ist (oder so ähnlich). Wenn ich den Java-Client-Prozess oder tippe ich so etwas wie töten:

pw.print(msg); 
out.close(); 

der Ausgang auf der Server-Seite ist:

_sending reply: "Request unrecognized/invalid" request="Hello, world!" 
send reply success 
now close connection 

Dieser Ausgang rechts (mit Ausnahme von „Antwort Erfolg senden“), aber im Fall des Hinzufügens:

out.close(); 

der Client kann die Antwort des Servers nicht empfangen. Weil der Socket geschlossen ist.

java.net.SocketException: Socket is closed 
at java.net.Socket.getInputStream(Socket.java:864) 
at MyServer.writeMessage(MyServer.java:56) 
at MyServer.test(MyServer.java:42) 
at MyServer.main(MyServer.java:30) 

bearbeiten

Ich versuchte pw.flush zu nennen(); und verschiedene Trennzeichen wie "\ n", "\ r", "\ r \ n" und "\ n \ r", aber der Server denkt immer noch, dass es noch etwas zu lesen gibt. Ich versuchte auch, DatagramSockets zu verwenden:

java.net.DatagramSocket dSocket = new java.net.DatagramSocket(); 
InetAddress address = InetAddress.getByName("localhost"); 
String msg = "Hello, world!"; 
byte[] buf = msg.getBytes(); 
java.net.DatagramPacket packet = new DatagramPacket(buf, buf.length, address, 6686); 

Aber der Server kann das Paket nicht annehmen.

Lösung

Das Rubin-Client so etwas wie ein socket.shutdownOutput tut(); (ruby: socket.shutdown 1) nach dem Aufruf von Puts. Ich habe den Java-Client-Code geändert:

out.write(msg); 
socket.shutdownOutput(); 

und es funktioniert!

Wie @Charly sagte: Ich muss ein "Protokoll" definieren. In meinem Fall darf ich keinen kommunikationsbezogenen Code ändern (im Server und im Ruby-Client), weil diese Funktionalität von einer anderen Gruppe von Forschern benutzt wird. So habe ich meinen Java-Client auf diese Weise zu modifizieren, dass es funktioniert die genauen gleichen Dinge an der genau gleichen Zeit wie das Rubin-Client (so etwas wie ein Protokoll).

Antwort

2

Printwriter-Puffer (wenn Autoflushing wahr ist) nur durch den Aufruf println oder printf gespült. Der Aufruf von print kann den Puffer nicht löschen (Javadoc). Versuchen Sie println aufzurufen oder verwenden Sie einen OutputStreamWriter direkt und flush(). Achten Sie darauf, den richtigen Zeichensatz zu verwenden (Sie können ihn im OutputStreamWriter-Konstruktor einrichten).

+0

Ich habe bereits pw.flush() verwendet, aber nichts wurde geändert. Jetzt habe ich versucht, OutputStreamWriter direkt zu verwenden: out = new OutputStreamWriter (socket.getOutputStream(), Charset.forName ("ISO-8859-1")); ... und out.write (msg); out.flush(); aber dasselbe Ergebnis. –

+0

Ich habe die Java-Client-Quelle geändert –

+0

Ich weiß wirklich nicht C++, aber sollten Sie nicht eine Art Trennzeichen haben, um das Ende der Nachricht an den Server anzuzeigen? Wie ich sehe, sendet Ihr Server das Echo nur, wenn die Verbindung geschlossen wird ... Zum Beispiel wird readLine() auf einem BufferedReader in Java nur beim Lesen von \ n oder a \ r zurückgegeben. – Charly

0

Schließen Sie den Strom bzw. es in einer Weise bündig wie folgt aus:

DataOutputStream dataOut = new DataOutputStream(socket.getOutputStream()); 
dataOut.writeUTF(s); 
dataOut.flush(); 
+0

Hallo Misch, DataOutputStream, writeUTF (msg) und flush(); funktioniert nicht. recv_count ist 15! auf dem Server (ich würde 13 oder 14 akzeptieren). Und der Ausgang: cout << "empfangen:" << Puffer << endl; ist leer. Es gibt keine Charaktere. –

0
while ((recv_count = recv(SocketFD, buffer, sizeof(buffer) - 1, 0)) > 0) { 
     if (recv_count == -1) { 

Ich weiß nicht, was dein Problem ist aber dieser Code ist sicherlich Unsinn. Es ist unmöglich, dass der innere Test jemals erfolgreich ist.

+0

Sie haben Recht. Es ist nur ein altes Codefragment. Du kannst es ignorieren. –

+0

Ich habe den C++ - Server-Code geändert –