Java客户端和C ++服务器通过TCP Socket发送和接收

时间:2013-04-09 13:12:29

标签: java c++ ruby sockets send

我有一个C ++服务器和两个客户端(ruby和java)。 一切都在64位linux机器上运行(java 1.7.0_17) ruby客户端完全正常工作,但java版本会产生问题。

在Java中,我尝试从客户端向服务器发送一个String。实际上,服务器收到了整个字符串,但服务器认为还有更多东西要接收。

ruby​​客户端看起来有点像这样:

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

这里的一切都很好。 ruby客户端发送一个字符串。服务器接收该字符串并发送回复。

Java版本如下:

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

另一方面有一个C ++服务器:

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

Java消息的服务器输出是:

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

然后没有任何反应。 问题是:

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

陷入了无尽的循环(或类似的东西)。 如果我终止Java客户端进程或输入类似:

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

服务器端的输出是:

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

此输出正确(“发送回复成功”除外),但在添加:

的情况下
out.close();

客户端无法收到服务器的回复。因为Socket已关闭。

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)

修改

我试着打电话给pw.flush();和“\ n”,“\ r”,“\ r \ n”和“\ n \ r”等不同的分隔符,但服务器仍然认为还有东西要读。我也尝试使用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);

但服务器无法接受该数据包。

解决方案

ruby​​-client执行类似socket.shutdownOutput(); (ruby:socket.shutdown 1)在调用puts之后。我更改了java-client-code:

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

它有效!

正如@Charly所说:我必须定义一个“协议”。在我的情况下,我不允许更改任何与通信相关的代码(在服务器和ruby-client中),因为此功能由另一组研究人员使用。所以我要以这种方式修改我的java-client,它与完全在ruby-client(像协议之类的东西)同时做完全相同的事情)。

3 个答案:

答案 0 :(得分:2)

PrintWriter缓冲区(当autoflush为true时)仅通过调用println或printf来刷新。调用print可能不会刷新缓冲区(Javadoc)。尝试直接调用println或使用OutputStreamWriter并使用flush()。 请注意使用正确的字符集(您可以在OutputStreamWriter构造函数中进行设置)。

答案 1 :(得分:0)

关闭流分别以这样的方式冲洗它:

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

答案 2 :(得分:0)

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

我不知道你的问题是什么,但这段代码肯定是胡说八道。内部测试不可能成功。