2013-04-09 12 views
5

Mam serwer C++ i dwóch klientów (ruby i java). Wszystko działa na 64-bitowej maszynie linux-owej (java 1.7.0_17) Klient ruby ​​działa w pełni, ale wersja java sprawia problemy.Klient Java i serwer C++ wysyłanie i odbieranie przez TCP Socket

W języku Java próbowałem wysłać ciąg od klienta do serwera. W rzeczywistości serwer otrzymał cały ciąg, ale serwer uważa, że ​​wciąż jest coś do odebrania.

Klient rubin wygląda trochę tak:

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

Tu wszystko działa poprawnie. Klient ruby ​​wysyła ciąg. Serwer odbiera ten ciąg i wysyła odpowiedź.

Java wersja wygląda następująco:

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

Po drugiej stronie znajduje się C++ serwera:

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

Wyjście serwer z java-wiadomości wynosi:

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

, a następnie nic się nie dzieje. Problemem jest to, że:

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

jest przechwycony w nieskończonej pętli (lub podobnym). Gdybym zabić proces Java-client lub wpisuję coś takiego:

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

efekt na stronie serwera jest:

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

To wyjście ma prawo (z wyjątkiem „wyślij sukces odpowiedź”), ale w przypadku dodawania:

out.close(); 

klient nie może odebrać odpowiedzi serwera. Ponieważ gniazdo jest zamknięte.

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) 

Edit

Próbowałem zadzwonić pw.flush(); i różne ograniczniki, takie jak "\ n", "\ r", "\ r \ n" i "\ n \ r", ale serwer nadal uważa, że ​​jest jeszcze coś do odczytania. Próbowałem również użyć 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); 

Ale serwer nie może przyjąć pakietu.

Rozwiązanie

Ruby-klient robi coś jak socket.shutdownOutput(); (ruby: socket.shutdown 1) po wywołaniu puts. Zmieniłem kod klienta java:

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

i to działa!

Jak powiedział @Charly: Muszę zdefiniować "protokół". W moim przypadku nie mogę zmienić żadnego kodu związanego z komunikacją (w serwerze i kliencie-ruby), ponieważ ta funkcjonalność jest używana przez inną grupę badaczy. Tak więc muszę zmodyfikować mojego klienta java w ten sposób, że robi to samo dokładnie w tym samym czasie, co klient-rubin (coś w rodzaju protokołu).

Odpowiedz

2

Bufor PrintWriter (gdy autoflup) jest prawdziwy) jest płukany tylko przez wywołanie println lub printf. Wywołanie print nie może opróżnić bufora (Javadoc). Spróbuj wywołać println lub użyj OutputStreamWriter bezpośrednio i flush(). Należy pamiętać o użyciu właściwego zestawu znaków (można go ustawić w konstruktorze OutputStreamWriter).

+0

Użyłem już pw.flush(), ale nic się nie zmieniło. Teraz próbowałem bezpośrednio użyć OutputStreamWriter: out = new OutputStreamWriter (socket.getOutputStream(), Charset.forName ("ISO-8859-1")); ... i out.write (msg); out.flush(); ale ten sam wynik. –

+0

Zmieniłem źródło klienta java –

+0

Naprawdę nie wiem C++, ale czy nie powinieneś mieć jakiegoś ogranicznika, który wskazuje koniec wiadomości na serwerze? Jak widzę, twój serwer wysyła echo tylko wtedy, gdy połączenie jest zamknięte ... Na przykład readLine() na BufferedReader w Javie powróci tylko podczas odczytu \ n lub \ r. – Charly

0

zamknąć strumienia odpowiednio przepłukać go w sposób jak poniżej:

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

Hi Misch, DataOutputStream, writeUTF (msg) i flush(); nie działa. recv_count jest 15! na serwerze (akceptowałbym 13 lub 14). A wynik: cout << "received:" << buffer << endl; jest pusty. Nie ma żadnych postaci. –

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

nie wiem jaki jest twój problem, ale ten kod jest oczywiście nonsensem. Niemożliwe jest, aby wewnętrzny test kiedykolwiek się powiódł.

+0

Masz rację. To tylko stary fragment kodu. Możesz to zignorować. –

+0

Zmieniłem kod serwera C++ –

Powiązane problemy