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).
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. –
Ho cambiato la sorgente java-client –
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