C++ 客户端套接字发送原始文件和文件大小,Java 客户端总是多获得 8 个字节。即使强制限制为 -8 字节文件也不可读

C++ client socket sends original file and file size, Java client always get 8 bytes more. Even after force limiting to -8 bytes file is unreadable

有一段时间,我被这个问题困扰

使用我在此处找到的一段 C++ 代码,在我看来应该可以很好地实际发送准确数量的数据,我猜问题出在 Java 代码或未知的地方。

此外,发送简单的 "Hello World" 数据时,传输正确完成。

如果有人能解决它,或提供宝贵的意见,我将不胜感激。 我是 运行 Windows 10 jdk1.8.0_221 和 Visual Studio 2022.

我知道将来可能需要在 return 中将 filesize 作为字符串和知识标志发送,但为简单起见,C++ 客户端仅发送一个包含已知数据量的文件.

这是Java的一面:

while(!Terminate)
{    
    byte[] bytes = new byte[1];//code was different for a real buffer 
    //...still +8 bytes
    while (in.available() > 0) 
    {
        in.read(bytes);
        out.write(bytes);
        out.flush();
    }
}
out.close();
int filesize = 15670;
int cnt = 0;
while (cnt<filesize)
{
    out.write(in.read());
    out.flush();
    cnt++;
}

这让我觉得保存时添加了 8 个字节。

C++代码:

int SendBuffer(SOCKET s, const char* buffer, int bufferSize, int chunkSize = 4 * 1024) {
    int l = -1;
    int i = 0;
    while (i < bufferSize) 
    {
        int l = send(s, &buffer[i], __min(chunkSize, bufferSize - i), 0);
        //int l = send(s, &buffer[i], bufferSize , MSG_DONTROUTE);
        int j = 0;
        std::cout << i << std::endl;
        while (l < 0) { Beep(433, 1000); j++; std::cout << "shiban l" << l << std::endl; l = send(s, &buffer[i], __min(chunkSize, bufferSize - i), 0); } // this is an error
        i += l;
    }
    return i;
}

int64_t SendFile(SOCKET s, const std::string fileName, int chunkSize) {

    const int64_t fileSize = GetFileSize(fileName);
    if (fileSize < 0) { return -1; }

    std::ifstream file(fileName, std::ifstream::binary);
    if (file.fail()) { return -1; }

    if (SendBuffer(s, reinterpret_cast<const char*>(&fileSize),
        sizeof(fileSize)) != sizeof(fileSize)) {
        return -2;
    }

    char* buffer = new char[chunkSize];
    bool errored = false;
    int64_t i = fileSize;
    auto bytes_sent = 0;
    while (i > 0) {
        const int64_t ssize = __min(i, (int64_t)chunkSize);
        if (!file.read(buffer, ssize)) { errored = true; break; }
        const int l = SendBuffer(s, buffer, (int)ssize);
        bytes_sent += l;
        int bi = 0;
        if (l < 0) { std::cout <<" err :"<< l<<std::endl; errored = true; break; }
        i -= l;
    }
    delete[] buffer;

    file.close();
    std::cout << "bytes_sent:" << bytes_sent << std::endl;
    return errored ? -3 : fileSize;
}

C++ 代码在发送文件数据之前发送文件大小(好),但没有进行足够的错误处理(坏),并且它没有以 platform-agnostic 格式发送文件大小(不好)。

没关系,因为显示的 Java 代码甚至没有在读取文件数据之前尝试读取文件大小(非常糟糕),也没有注意 return in.read() 的值以了解 实际 接收了多少字节。但即使是,C++ 代码也将大小作为 8 字节整数发送(大文件 > 2GB 时需要),但 Java 代码使用 4 字节整数代替(错误)。 C++ 还在 SendFile().

中为 bytes_sent 使用 4 字节整数

试试像这样的东西:

BufferedInputStream bis = new BufferedInputStream(in);
DataInputStream dis = new DataInputStream(bis);
long filesize = dis.readLong();
if (filesize > 0)
{
    byte[] bytes = new byte[4*1024];
    do
    {
        int chunkSize = (int) Math.min(filesize, (long) bytes.length);
        dis.readFully(bytes, 0, chunkSize);
        out.write(bytes, 0, chunkSize);
        out.flush();
        filesize -= chunkSize;
    }
    while (filesize > 0);
}
out.close();
bool SendBuffer(SOCKET s, const char* buffer, int bufferSize) {
    while (bufferSize > 0)
    {
        int numSent = send(s, buffer, bufferSize, 0/*MSG_DONTROUTE*/);
        if (numSent < 0) {
            Beep(433, 1000);
            return false;
        }
    }
    return true;
}

int64_t SendFile(SOCKET s, const std::string fileName, int chunkSize) {

    const int64_t fileSize = GetFileSize(fileName);
    if (fileSize < 0) { return -1; }

    std::ifstream file(fileName, std::ifstream::binary);
    if (file.fail()) { return -1; }

    const int64_t tmp = htonll(fileSize); // see 
    if (!SendBuffer(s, reinterpret_cast<const char*>(&tmp), sizeof(tmp))) {
        return -2;
    }

    std::vector<char> buffer(chunkSize);
    bool errored = false;
    int64_t bytes_sent = 0;

    while (fileSize > 0) {
        int ssize = static_cast<int>(std::min<int64_t>(fileSize, chunkSize));
        if (!file.read(buffer.data(), ssize)) { errored = true; break; }
        if (!SendBuffer(s, buffer.data(), ssize)) { errored = true; break; }
        fileSize -= ssize;
    }

    file.close();

    if (errored) {
        std::cout << "err" << std::endl;
        return -3;
    }

    std::cout << "bytes_sent:" << bytes_sent << std::endl;
    return bytes_sent;
}