如何使用libssh2判断传输是否完成?

huangapple go评论61阅读模式
英文:

How to tell when a transfer is complete with libssh2?

问题

我正在使用 libssh2 进行 scp 文件传输,总体上是有效的。然而,我目前正在尝试从一个奇怪的 SSH 服务器读取一些文件,该服务器不支持提前检索文件的元数据。因此,我不知道我要下载的文件实际大小有多大。

我发现,如果数据完整,libssh2 会在接收到的数据末尾放置一个空字节,这对于文本文件是可以的,但对于二进制数据将失败或导致不确定性,因为二进制数据本身可能包含一个字节 0x00。

假设这是您的代码:

LIBSSH2_CHANNEL* ch = libssh2_scp_recv2(session, remote_file_path, NULL);

ssize_t bytes_received = 0;
bool eof_received = false;
if (ch) {
    do {
        char buf[1024] = {0};
        bytes_received = libssh2_channel_read(ch, buf, sizeof(buf));

        eof_received = (buf[bytes_received - 1] == 0x00));
        printf("Received %d bytes.\n", bytes_received);
    } while (bytes_received > 0 && !eof_received);
}

如果我传输一个大小大于 1024 字节的二进制文件,并且碰巧文件的第 1024 个字节是 0x00,上述代码将认为已达到文件结尾并停止传输。
我还测试过 libssh2_channel_eof,但这始终返回 false。

那么,如何在不知道预期文件大小的情况下正确确定何时完全通过 SCP 下载文件呢?

英文:

I'm using libssh2 for scp file transfer which in general is working. However, I'm currently trying to read some file from a weird SSH server which doesn't support to retrieve the meta data of the file upfront. Thus I don't know how big the file really is that I want to download.

I found out that libssh2 is putting a null byte at the end of the received data if the data is complete, which is ok for text files, but will fail or lead to incertainties for binary data which itself may contain a byte 0x00.

Assume this code:

LIBSSH2_CHANNEL* ch = libssh2_scp_recv2(session, remote_file_path, NULL);

ssize_t bytes_received = 0;
bool eof_received = false;
if (ch) {
    do {
        char buf[1024] = {0};
        bytes_received = libssh2_channel_read(ch, buf, sizeof(buf));

        eof_received = (buf[bytes_received - 1] == 0x00));
        printf("Received %d bytes.\n", bytes_received);
    } while (bytes_received > 0 && !eof_received);
}

If I transfer a binary file > 1024 bytes and by coincidence the 1024th byte of the file is 0x00, the code above will think EOF is reached and stop the transfer.
I also tested libssh2_channel_eof but this always gives false.

So, how can we properly know when a file is completely downloaded via SCP without knowing the expected filesize upfront?

答案1

得分: 2

libssh2的LIBSSH2_SESSION结构包含一些字段,用于scp接收操作。在接收文件时,字段session->scpRecv_size将包含正在传输的文件的大小。还有其他字段用于文件的权限和时间戳。

正如您所指出的,将libssh2_struct_stat*传递给libssh2_scp_recv2()调用会导致scp接收逻辑在远程scp调用中包含"-p"选项。 stat结构最终是从会话结构的字段填充的,大约在这里。如果您不想将"-p"发送到远程scp调用中,那么应该将第三个参数传递为nulllibssh2_scp_recv2(),并从session->scpRecv_size获取预期的文件大小。

英文:

the libssh2 LIBSSH2_SESSION struct has some fields used for scp receive operations. While receiving a file, the field session->scpRecv_size will contain the size of the file being transferred. There are other fields for the file's permissions and timestamps.

As you've indicated, passing a libssh2_struct_stat* to the libssh2_scp_recv2() call causes the scp receive logic to include the "-p" option in the remote scp invocation. The stat struct is eventually populated from the fields of the session struct around here. If you don't want to send "-p" to the remote scp invocation, then you should pass null as the third argument to libssh2_scp_recv2(), and get the expected file size from session->scpRecv_size.

答案2

得分: -1

以下是翻译好的部分:

"scp.c"的官方示例展示了如何执行此操作,链接在 https://github.com/libssh2/libssh2/blob/master/example/scp.c#L152C17-L152C25

channel = libssh2_scp_recv2(session, scppath, &fileinfo);
while(got < fileinfo.st_size) {
    char mem[1024];
    int amount = sizeof(mem);
    ssize_t nread;

    if((fileinfo.st_size - got) < amount) {
        amount = (int)(fileinfo.st_size - got);
    }

    nread = libssh2_channel_read(channel, mem, amount);
    if(nread > 0) {
        write(1, mem, nread);
    }
    else if(nread < 0) {
        fprintf(stderr, "libssh2_channel_read() 失败:%d\n",
                (int)nread);
        break;
    }
    got += nread;
}
英文:

The official example of scp.c shows how to do it https://github.com/libssh2/libssh2/blob/master/example/scp.c#L152C17-L152C25 .

    channel = libssh2_scp_recv2(session, scppath, &amp;fileinfo);
    while(got &lt; fileinfo.st_size) {
        char mem[1024];
        int amount = sizeof(mem);
        ssize_t nread;

        if((fileinfo.st_size - got) &lt; amount) {
            amount = (int)(fileinfo.st_size - got);
        }

        nread = libssh2_channel_read(channel, mem, amount);
        if(nread &gt; 0) {
            write(1, mem, nread);
        }
        else if(nread &lt; 0) {
            fprintf(stderr, &quot;libssh2_channel_read() failed: %d\n&quot;,
                    (int)nread);
            break;
        }
        got += nread;
    }

huangapple
  • 本文由 发表于 2023年7月10日 14:57:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/76651334.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定