英文:
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
调用中,那么应该将第三个参数传递为null
给libssh2_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, &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() failed: %d\n",
(int)nread);
break;
}
got += nread;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论