【问题标题】:TCP-Server sending a file in a packet structure (to a non Java client)TCP-Server 以数据包结构发送文件(到非 Java 客户端)
【发布时间】:2018-08-02 18:38:16
【问题描述】:

我又问了其中一个问题:P
由于我正在将我的 C++ 服务器移植到 Java 服务器(并且几乎完成),我只缺少一件事:
发送文件。
我不知道如何在 Java 中构造数据包以通过 DataOutputStream 发送它。
在 C++ 中,我以这种方式准备了数据包(为 file_size 保留前 4 个字节,其余的文件本身):

char *pData = new char[file_size];

memcpy(pData, charArray.data(), file_size);

char *packet = new char[file_size + 4];
memset(packet, 0, file_size + 4);

*(int*)(packet) = file_size;
memcpy((char*)(packet + 4), pData, file_size);

int r = file_size + 4;
sendall(stream, packet, &r);

我希望你能在这里帮助我,我能够构造简单的数据包,但是这个让我头疼 :P
我是合并字节还是如何在 Java x..x 中完成 C++ 代码
提前致谢!

发送函数:

int sendall(TCPStream *s, char *buf, int *len)
{
    int total = 0;
    int bytesleft = *len;
    int n;

    while(total < *len)
    {
        n = s->send(buf+total, bytesleft);
        if (n == -1) break;
        total += n;
        bytesleft -= n;
    }

    *len = total;

    return n ==-1 ? -1 : 0;
}

【问题讨论】:

  • 那么问题是什么?您发送 4 个字节的大小,然后是文件内容的所有字节。您是否在问如何以正确的字节顺序发送 4 字节大小?您正在使用DataOutputStream,它首先发送带有高字节的int 值,所以如果这是C++ 所做的,则调用writeInt(int v),然后调用write(byte[] b, int off, int len)。如果 C++ 先发送低字节,那你为什么要使用DataOutputStream?
  • 既然你在移植你可能不关心C++笔记,但是,从charArray.data()复制到pData有什么意义呢?看起来你可以节省一个步骤和memcpy((char*)(packet + 4), charArray.data(), file_size);,或者省去很多麻烦,然后分别发送file_size和charArray.data()。 TCP 是一个流,因此除非您在sendall 中添加了额外的协议标头,否则您决定什么是数据包并不重要。 TCP 会以它想要的任何大小/形状的 blob 发送您的消息。
  • 再想一想,这也适用于java。 sendall 是做什么的?如果它只是标准套接字写入的精简包装,您可以将所有工作减少到一个DataOutputStream,一个调用writeInt 和一个调用write。如果没有sendall 的代码或猜测,则无法回答问题。
  • Except for Endian. 传输file_size 时注意字节序。 Java 总是说大端,除非你告诉它不这样做。 C++ 能说出硬件的原生特性。
  • C++ 代码可以简化为sendall(stream, (char*)&amp;file_size, sizeof (file_size)); sendall(stream, charArray.data(), file_size);。再次注意字节序并确保 int 是 32 位的。 Better still use uint32_t from &lt;cstdint&gt;

标签: java c++ sockets tcp tcpserver


【解决方案1】:

该 C 代码的 Java 等价物是:

int file_size = ...;
byte[] file_data = ...;

byte[] packet = new byte[file_size + 4];
ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).putInt(file_size);
System.arraycopy(file_data, 0, packet, 4, file_size);

需要先确认发送的文件大小是高字节还是低字节,如果需要改成BIG_ENDIAN。

由于 C 代码只是将文件大小添加为 int,并且可能在 Intel 处理器上运行,因此结果是 LITTLE_ENDIAN,这就是我在上面的代码中指定的原因。但是作为@paulsm4 said,您应该对此进行测试。

【讨论】:

  • 关于byte order:套接字“网络顺序”和Java字节顺序都是Big-Endian。大多数主机是 Intel CPU (Little-Endian)。原始的 C++ 代码只是“发送字节”(没有 htonX 或等效的)。因此,尽管上面的代码 应该 工作......我肯定会 TEST 它。原始代码应该使用htonl() 表示“file_size”...
  • @paulsm4 你说得对,大多数主机是 Intel,因此是 LITTLE_ENDIAN,由于 C 代码只写了 int 值,我将默认情况下将答案更改为 LITTLE_ENDIAN,所以它可能适用于 OP is-as。
  • 我知道字节顺序和 endiness 问题,在我的 Java 程序中,它在发送之前就已经处理过了。虽然@Andreas 代码移植在我身边做了这件事,但我想我现在知道 ByteBuffer 将如何在这些领域工作。 user4581301 我是一步一步做的,所以代码是这样的^^谢谢大家!
猜你喜欢
  • 1970-01-01
  • 2022-01-23
  • 1970-01-01
  • 2015-12-26
  • 2011-08-15
  • 1970-01-01
  • 2021-05-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多