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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15902898/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 21:14:19  来源:igfitidea点击:

Java client and a C++ server send and receive via TCP Socket

javac++rubysocketssend

提问by MartinO.

I have a C++ server and two clients (ruby and java). Everything is running on a 64-bit linux-machine (java 1.7.0_17) The ruby client is fully working, but the java version makes problems.

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

In Java I tried to send a String from the client to the server. Actually the Server received the entire String, but the server thinks there is still something more to receive.

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

The ruby client looks a little bit like this:

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

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

Everything here is working fine. The ruby client sends a string. The server receives that string and sends a reply.

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

The Java Version looks like:

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

On the other side there is a C++ Server:

在另一边有一个 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;
}

The server output from the Java-message is:

Java 消息的服务器输出是:

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

and then nothing happens. The problem is that:

然后什么也没有发生。问题在于:

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

is catched in an endless loop (or something like that). If I kill the Java-client process or I type something like:

陷入无限循环(或类似的东西)。如果我终止 Java 客户端进程或键入以下内容:

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

the output on the server side is:

服务器端的输出是:

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

This output is right (except "send reply success"), but in case of adding:

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

out.close();

the client can't receive the reply of the server. Because the Socket is closed.

客户端收不到服务器的回复。因为 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)

Edit

编辑

I tried to call pw.flush(); and different delimiters like "\n", "\r", "\r\n" and "\n\r" but the server still thinks there is still something to read. I also tried to use DatagramSockets:

我试图调用 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);

But the server can't accept the packet.

但是服务器不能接受数据包。

Solution

解决方案

The ruby-client does something like a socket.shutdownOutput(); (ruby: socket.shutdown 1) after the call of puts. I changed the java-client-code:

ruby-client 做一些类似于 socket.shutdownOutput(); 的事情。(ruby: socket.shutdown 1) 在调用 puts 之后。我更改了 java-client-code:

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

and it works!

它有效!

As @Charly said: I have to define a "protocol". In my case I'm not allowed to change any communication related code (in the server and the ruby-client) because this functionality is used by a another group of researchers. So I've to modify my java-client in that way, that it does the exactsame things at the exactsame time as the ruby-client (something like a protocol).

正如@Charly 所说:我必须定义一个“协议”。就我而言,我不允许更改任何与通信相关的代码(在服务器和 ruby​​ 客户端中),因为该功能被另一组研究人员使用。所以我修改这样我的Java客户端,它确实的确切同样的事情在精确的同时红宝石客户端(如协议的东西)。

采纳答案by Charly

PrintWriter buffer (when autoflush is true) is only flushed by calling println or printf. Calling print may not flush the buffer (Javadoc). Try calling println or use a OutputStreamWriter directly and flush(). Be aware of using the right charset (You can set it up in OutputStreamWriter constructor).

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

回答by Jan Piel

Close the stream respectively flush it in a way like this:

关闭流以如下方式分别冲洗它:

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

回答by user207421

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

I don't know what your problem is but this code is certainly nonsense. It is impossible for the inner test ever to succeed.

我不知道你的问题是什么,但这段代码肯定是无稽之谈。内测永远不可能成功。