【问题标题】:Sending strings over the net from C++ client to Java server通过网络从 C++ 客户端向 Java 服务器发送字符串
【发布时间】:2012-02-20 16:41:01
【问题描述】:

我正在编写一个客户端/服务器应用程序,其中客户端是用 C++ 编写的,而服务器是 Java。它们之间的通信是通过UDP协议进行的。 他们需要通过网络交换字符串消息。 现在,通信工作很多,客户端发送消息,服务器接收它,但我注意到接收到的字符串,在 Java 端,就像中继一样。我的意思是,如果我尝试将其显示到控制台上,使用以下功能:

System.out.println("This is the message received " 
                           + message + " by the client just now");

我得到的结果是:

This is the message received *message*

将字符串“by the client just now”中继出来。

我认为这是由于Java和C++之间的一些不兼容,但我找不到解决方案。

编辑: 这是接收器的代码:

byte[] bytes = _packet.getData(); // Datagram Packet
hostName = getStringFromBytes(bytes, 0, 15);

(...)

private String getStringFromBytes (byte[] bytes, int lowerBound, int length) 
{
    byte[] bufferBytes  = new byte[length];
    System.arraycopy(bytes, lowerBound, bufferBytes, 0, length);

    return new String(bufferBytes).trim();
}

和发件人:

 if(sendto(_socket, buffer, BUFFER_LEN, 0, (struct sockaddr*) &_serverAddress, addressLenght) == -1)
    cout << "Trasmission failed!\n" << endl;

其中 buffer 是一个字符数组。

【问题讨论】:

  • 消息可能是0-终止的?
  • 一旦遇到问题,它就不是 java vs C++ 的事情了。基于@BoBTFish,您应该尝试使用 message.trim() 删除空格和 ascii 控制字符。
  • 我已经更新了帖子,插入了代码。 trim() 已经完成了,但我还是不知道。
  • 我的猜测是您正在从 c++ 发送一个以 null 结尾的 char[] 并且您的 JAVA 代码没有正确处理它。
  • String.trim 删除 ASCII 中小于或等于空格的前导和尾随字符。因此,如果缓冲区中的结束字节为 32(int)或更少,它就可以工作。如果不是,则结束字节可能表示修剪无法捕获的某些控制字符。

标签: java c++ string network-programming udp


【解决方案1】:
if(sendto(_socket, buffer, BUFFER_LEN, 0, (struct sockaddr*) &_serverAddress, addressLenght) == -1)

这一行似乎表明缓冲区是一个 c 字符串。如果是这种情况,您需要在服务器端解析出额外的 NULL 字符。 c 字符串中的 NULL 字符可能会导致 JAVA 代码在看到 NULL 字符后立即停止处理该字符串——这是它应该做的。

您可能只需要修剪 JAVA 代码中字符串的最后一个字符。请记住,C 字符串的末尾总是有一个额外的字符——一个 NULL 字符。

另外,BUFFER_LEN 是宏吗?它被定义为什么?尝试只发送实际的缓冲区长度,而不是预定义的长度。

std::string buffer = "Your Message";

if(sendto(_socket, buffer.c_str(), buffer.length(), ...)

一般来说,在 C++ 中,尽可能使用 std::string,而不是 char*。

【讨论】:

  • 看看这个,BUFFER_LEN 是否可能是一些常量或宏用于定义数组的大小?然后您可能会收到“实际消息\0somegarbage”,在这种情况下 \0 不会被修剪掉,但仍会结束输出。
  • @BoBTFish 绝对!这很可能是问题所在。
【解决方案2】:

一种可能性是您并不总是在缓冲区中收到预期的 [长度]。因此,当您转换为字符串时,缓冲区末尾有随机字节。其中一些字节可能表示与控制台输出混淆的控制代码。

认为 String.trim 会从字符串中删除 NULL (\0) 字符,但是,它不会删除值超过 '\u0020' 的字符。 (参见 javadoc:http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/String.html#trim())

如果正确,那么您需要检查您的字符串转换并且:

  • 以某种方式检测字符串结尾,与您预期的字节缓冲区长度无关。也许通过搜索第一个 NULL 终止符。或者,
  • 根据您预期的字符串编码,替换\删除字符串中超出 String.trim 将执行的所有空格字符。

【讨论】:

    【解决方案3】:

    您应该尝试在消息的开头添加“消息”的实际大小

        std::string strMessage = "My Message";
    
        char* pBuffer = new char[sizeof(int) + strMessage.size()];
    
        int iSize = strMessage.size();
        memcpy(pBuffer, &iSize, sizeof(int));
        memcpy(pBuffer + sizeof(int), strMessage.c_str(), strMessage.size());
    
    
        if(sendto(_socket, pBuffer, sizeof(int) + iSize, 0, (struct sockaddr*) &_serverAddress, addressLenght) == -1)
    
    ...
    
    delete pBuffer;
    

    然后在 Java 端,您读取前 4 个字节(假设在两个系统上 int 的 sizeof 都是 4),然后使用您读取的数字创建字符串。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-06-25
      • 2018-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-12
      相关资源
      最近更新 更多