2013-04-09 20 views
5

Ho un server C++ e due client (ruby e java). Tutto è in esecuzione su una macchina Linux a 64 bit (java 1.7.0_17) Il client ruby ​​è completamente funzionante, ma la versione java presenta problemi.Il client Java e un server C++ inviano e ricevono tramite TCP Socket

In Java ho provato a inviare una stringa dal client al server. In realtà il server ha ricevuto l'intera stringa, ma il server pensa che ci sia ancora qualcosa da ricevere.

Il cliente rubino sembra un po 'come questo:

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

Tutto qui sta lavorando bene. Il client ruby ​​invia una stringa. Il server riceve quella stringa e invia una risposta.

la versione Java assomiglia:

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

Dall'altro lato c'è una C Server ++:

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

L'output server dal Java-messaggio è:

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

e poi non succede nulla. Il problema è che:

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

catched in un ciclo infinito (o qualcosa di simile). Se uccido il processo Java client o digito qualcosa di simile:

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

l'uscita sul lato server è:

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

Questa uscita è a destra (ad eccezione di "inviare successo risposta"), ma in caso di aggiunta:

out.close(); 

il client non può ricevere la risposta del server. Perché lo zoccolo è chiuso.

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) 

Modifica

Ho provato a chiamare pw.flush(); e diversi delimitatori come "\ n", "\ r", "\ r \ n" e "\ n \ r" ma il server pensa ancora che ci sia ancora qualcosa da leggere. Ho anche provato a utilizzare DatagramSockets:

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

Ma il server non può accettare il pacchetto.

Soluzione

Il rubino-cliente fa qualcosa di simile a un socket.shutdownOutput(); (ruby: socket.shutdown 1) dopo la chiamata di puts. Ho cambiato il codice java-client:

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

e funziona!

Come @Charly ha detto: Devo definire un "protocollo". Nel mio caso non sono autorizzato a modificare alcun codice relativo alla comunicazione (nel server e nel ruby-client) perché questa funzionalità è utilizzata da un altro gruppo di ricercatori. Quindi devo modificare il mio java-client in questo modo, che fa lo esatto nello stesso esatto stesso tempo del ruby-client (qualcosa come un protocollo).

risposta

2

Il buffer PrintWriter (quando autoflush è true) viene svuotato solo chiamando println o printf. La chiamata alla stampa potrebbe non scaricare il buffer (Javadoc). Prova a chiamare println o usa OutputStreamWriter direttamente e flush(). Attenzione all'uso del set di caratteri giusto (è possibile configurarlo nel costruttore di OutputStreamWriter).

+0

Ho già usato pw.flush() ma non è stato modificato nulla. Ora ho provato a utilizzare direttamente OutputStreamWriter: out = new OutputStreamWriter (socket.getOutputStream(), Charset.forName ("ISO-8859-1")); ... e out.write (msg); out.flush(); ma lo stesso risultato. –

+0

Ho cambiato la sorgente java-client –

+0

Non so davvero C++ ma non dovresti avere qualche tipo di delimitatore per indicare la fine del messaggio al server? Come vedo, il tuo server invia l'eco solo quando la connessione è chiusa ... Ad esempio readLine() su BufferedReader in Java verrà restituito solo quando si legge \ n o a \ r. – Charly

0

chiudere il flusso a filo, rispettivamente, in un modo simile a questo:

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

Hi Misch, DataOutputStream, writeUTF (msg) e flush(); non funziona recv_count è 15! sul server (accetterei 13 o 14). E l'output: cout << "received:" << buffer << endl; è vuoto. Non ci sono personaggi –

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

non so che cosa il vostro problema è che questo codice è certamente una sciocchezza. È impossibile che il test interiore abbia mai successo.

+0

Hai ragione. È solo un vecchio frammento di codice. Puoi ignorarlo. –

+0

Ho cambiato il codice del server C++ –