有任何方法可以通过SSH连接打开和读取文件

there is any way to open and read a file over a SSH connection?

本文关键字:读取 文件 连接 任何 方法 可以通过 SSH      更新时间:2023-10-16

我可以访问一些有大量数据的服务器。我无法在电脑上复制全部数据。

我无法在服务器上编译我想要的程序,因为服务器没有我需要的所有库。

我不认为服务器管理员会很高兴看到我来并要求他为我安装一些libs…

所以,我想知道是否有一种方法可以打开一个文件,比如

FILE *fopen(const char *filename, const char *mode);

void std::ifstream::open(const char* filename,  ios_base::openmode mode = ios_base::in);

而是通过SSH连接。然后像我在普通程序中那样读取文件。

计算机和服务器都在运行linux

我假设你在linux笔记本电脑上工作,远程机器是某台超级计算机。

第一个非技术性建议:首先请求权限以远程访问数据。在某些工作场所,即使技术上可行,你也不允许这样做。

出于这个目的,您可以使用libssh,但您需要一些编码和阅读它的文档。

您可以考虑使用一些FUSE文件系统(在您的笔记本电脑上(,例如一些sshfs;然后您将能够访问一些超级计算机文件作为/sshfilesystem/foo.bar(。这可能是最慢的解决方案,也可能不是一个非常可靠的解决方案。我真的不推荐它。

您可以请求使用NFS装载的权限。

也许你可以考虑使用一些HTTP/HTTPS客户端库(如libcurl(进行HTTPS访问(如果远程计算机为你的文件提供了HTTPS访问((或者反过来,使用一些HTTP-HTTPS服务器库,如libonion(

你可以(但首先要征得许可!(通过OpenSSL或libgnutls 使用一些TLS连接(例如,在远程超级计算机上手动启动类似服务器的程序(

最后,您应该考虑在远程计算机上安装(即礼貌地要求在远程超级计算机上安装(或使用一些数据库软件(如PostgreSQL或MariaDB或Redis或MongoDB服务器(,使您的程序成为数据库客户端应用程序。。。

顺便说一句,如果你随机访问几十个TB大小的文件(每次运行读取文件中的几千字节(,或者访问一百万个文件,其中给定的运行通过顺序读取只访问其中的十几个文件,每个文件的大小都合理(几兆字节(,情况可能会有所不同。换句话说,DNA数据、视频电影、HTML文档、源代码。。。都是不同的情况!

好吧,你的问题的答案是no,正如已经说过的几次(除非你考虑自己实现ssh这超出了理智的范围(。

但是,当你描述你的真实问题时,它可能只是问错了问题,所以——寻找替代方案:

备选方案1

将要静态使用的库链接到二进制文件。假设您想静态链接libfoo

  • 确保在库搜索路径中有libfoo.a(库的对象存档(。通常,您的发行版提供的库的开发包已经包含了它,如果没有,请自己编译该库,并提供创建静态库的选项

  • 假设使用GNU工具链,使用以下标志构建程序:-Wl,-Bstatic -lfoo -Wl,-Bdynamic(而不仅仅是-lfoo(

备选方案2

像往常一样创建二进制文件(与动态库链接(,并将该库(libfoo.so(放在服务器上的~/lib中。然后用LD_LIBRARY_PATH=~/lib ./a.out在那里运行二进制文件。

您可以通过SSH连接将部分文件复制到您的计算机:

  • 使用dd命令将源文件的一部分复制到临时文件
  • 使用scprsync将临时文件复制到本地邮箱

如果需要多次执行,可以创建一个shell脚本来自动执行此操作。

您可以在ssh命令中使用popen,而不是在路径上使用fopen。(不要忘记,从popen获得的FILE *流是用pclose而不是fclose封闭的(。

您可以通过编写一个封装popen的函数来简化接口。该函数只接受远程文件名,然后生成ssh命令来获取该文件,正确地转义所有内容,如文件名中的空格、shell元字符等等。

FILE *stream = popen("ssh user@host cat /path/to/remote/file", "r");
if (stream != 0) {
   /* ... */
  pclose(stream);
}

popen有一些缺点,因为它处理shell命令。因为ssh的参数也是在远程端处理的shell命令,所以它引发了双重转义的问题:将命令作为shell命令传递。

要做一些更健壮的事情,可以使用pipe创建一个管道,然后使用forkexec*创建ssh进程,安装管道的写端作为其stdout,并使用fdopen在父进程中管道的读端创建FILE *流。这样,就可以准确地控制传递给进程的参数:至少在本地,您没有运行shell命令。

您不能直接(1(使用fopen((或ifstream::open通过ssh打开文件。但是您可以利用现有的ssh二进制文件。只需让您的程序从stdin读取,然后通过ssh:将文件传输到stdin

ssh that_server cat /path/to/largefile | ./yourprogram

(1( 好吧,如果您使用sshfs装载远程系统,您可以通过ssh访问这些文件,就好像它们是本地的一样。