Como copiar um arquivo que ainda está sendo gravado por ssh?

20

Aqui está a situação:

  1. Estou carregando um arquivo grande do cliente A para um servidor usando sftp.
  2. Também preciso baixar esse arquivo do servidor para o cliente B sobre ssh.

O que eu gostaria de fazer é iniciar a transferência do servidor para o cliente B quando o upload ainda estiver acontecendo do cliente A.

Qual é o melhor método / ferramenta para fazer isso?

ATUALIZAÇÃO :

As respostas até agora são interessantes - lerei e testarei todas elas. Pontos de bônus por respostas que não dependem do controle de como o Cliente A está carregando o arquivo. (ou seja, a única coisa que sabemos do cliente A é que o arquivo está sendo gravado em um nome de arquivo conhecido.)

Steven D
fonte
Ooo, boa pergunta. Isso é certamente possível, mas não estou ciente de nada que o implemente.
Michael Mrozek

Respostas:

10

Para um único arquivo, em vez de usar SFTP, você pode canalizar o arquivo pelo ssh usando catou pvno lado de envio e teeno servidor do meio para enviar os dados para um arquivo lá e enviar uma cópia pelo outro link ssh do outro lado. apenas grava os dados em um arquivo. O vodu exato exigido deixarei como um exercício para o leitor, pois não tenho tempo para jogar agora (desculpe). Esse método funcionaria apenas se o segundo destino estiver acessível ao público via SSH, o que pode não ser o caso, conforme você o descreve como uma máquina cliente.

Outra abordagem, que é menos "executar e aguardar", mas que pode ser mais fácil, pode ser usada rsyncentre o servidor e o cliente B. Na primeira vez em que você executa, pode obter uma cópia parcial dos dados, mas é possível executar novamente para obter mais dados posteriormente (com uma execução final quando a transferência do Cliente1-> Servidor estiver concluída). Isso funcionará apenas se o servidor colocar os dados diretamente no nome correto do arquivo durante a transferência SFTP (às vezes, você verá os dados entrando em um arquivo temporário que será renomeado assim que o arquivo for completamente transferido - isso é feito para atualização do arquivo mais atômica, mas inutiliza a idéia rsync). Você também pode usar o rsync para a transferência C1-> S em vez do scp (se você usar o--inplaceopção para evitar o problema mencionado acima) - o uso do rsync também protegeria contra a necessidade de reenviar tudo se a conexão C1-> Server apresentar problemas durante uma grande transferência (eu costumo usar em rsync --inplace -a --progress <source> <dest>vez de scp / sftp quando o rsync estiver disponível, por este comportamento de "transferência de currículo").

Para resumir o acima, executando:

rsync --inplace -a --progress <source> user@server:/<destination_file_or_folder>

no client1 em execução

rsync --inplace -a --progress user@server:/<destination_file_or_folder> <destination_on_cli2>

no client2 repetidamente até que a primeira transferência seja concluída (depois execute novamente para garantir que você tenha tudo). rsyncé muito bom em transferir apenas o mínimo absoluto necessário para atualizar um local em vez de transferir todo o lote a cada vez. Para a paranóia, você pode querer adicionar a --checksumopção aos comandos rsync (o que levará muito mais tempo da CPU para arquivos grandes, mas não resultará na transferência de mais dados a menos que seja necessário) e, para velocidade, a --compressopção ajudará se os dados você está transferindo ainda não está em um formato compactado.

David Spillett
fonte
5

Não posso tentar no momento, então isso pode falhar: Minha idéia é a seguinte: monte o diretório em que o arquivo está chegando no cliente B, por exemplo, com sshfs para / mnt / server no sistema de arquivos do cliente b. Então

tail -c +0 -f /mnt/server/thefileinquestion > ~/finalfile
fschmitt
fonte
/ usr / bin / tail: não é possível abrir `+0 'para leitura: não
existe
Desculpe, estava faltando um -c. Corrigi-o na resposta acima.
Fschmitt 01/10/10
ok, um problema que vejo com isso é que o comando não termina (-f -> siga ...). É preciso emitir um sigQUIT ou algo assim, quando você tiver certeza de que a pergunta do arquivo foi completamente escrita. Btw, dependendo da versão da cauda e do fs, a cauda realiza a pesquisa interna do arquivo (por exemplo, a cada segundo).
maxschlepzig
Eu tive um caso: gravar um arquivo de vídeo no meu disco rígido, mas queria copiar para uma memória Flash USB externa para poder entregá-lo a uma pessoa assim que a gravação for interrompida. Tentei várias rsync --appende depois verifiquei, md5summas os arquivos nunca foram correspondentes. tail -c +0fez o trabalho para mim. Eu também costumava pv -pteramonitorar o progresso da cauda, ​​isso me permite ver se está funcionando. Ainda não terminei de verificar o md5s para verificar se funcionava, mas está ótimo.
Unfa 19/11
@unfa Atualize seu comentário adicionando uma resposta abaixo (isto é, não um comentário).
Xofo 16/07
1

Eu acho que isso deve funcionar:

user@clientA:~$ cat file | ssh server "cat > dest"

e depois

user@clientB:~$ ssh server "tail +0 -f dest" > file

Adicione o comando pv se desejar ver sua taxa de transferência.

escutas telefônicas
fonte
Você quis escrever tail -c +0?
dessert
1

Você poderia usar um fifo para isso. Para simplificar primeiro, sem o ssh envolvendo apenas dois xterms:

No xterm A:

$ mkfifo fif
$ cat test.tar.gz | tee copy.tar.gz > fif

No xterm B:

$ cat fif > dest.tar.gz
$ cmp test.tar.gz dest.tar.gz
$ echo $?
0
$ cmp test.tar.gz copy.tar.gz
$ echo $?
0

Com o ssh, deve haver algo nesse sentido - talvez você precise desativar o caractere de escape no ssh (-e none):

cliente A:

 $ ssh server mkfifo fif
 $ cat src.tar.gz | ssh "tee fif > copy.tar.gz"

cliente B:

 $ ssh server cat fif > dest.tar.gz
maxschlepzig
fonte
1

Eu tenho uma situação que precisa de uma solução como o cartaz original solicitado. Estou gravando um jogo de hóquei no meu computador em um local e gostaria de assistir na minha TV em outro local. O link entre os dois locais permite que a cópia chegue a cerca de 1,3 Mb / se o vídeo de gravação é cerca de 1,5 Mb / s. Então, eu quero copiar o arquivo quando ele começar a gravar. Dessa forma, meu jogo de 3 horas será copiado em aproximadamente 3,5 horas. Então, eu copio-o assim que começa a gravar e posso começar a assisti-lo 30 minutos após o início. Então eu posso assistir sem interrupções, quase em tempo real. Ou seja, desde que eu consiga copiá-lo enquanto estiver gravando o novo arquivo. O problema com ferramentas como rsync e scp é que elas examinam o tamanho do arquivo quando você inicia a cópia e, uma vez que ele copia essa quantidade de dados, ele sai; mesmo que o arquivo tenha crescido mais que o dobro durante essa cópia. E, se estiver usando o rsync em um loop para copiá-lo quando parar, quando o próximo rsync terminar, reconstruirá o arquivo de destino e matará o meu player de vídeo. Preciso reiniciar a visualização e avançar rapidamente para onde quer que estivesse no programa quando de repente o matou. Eu queria uma solução melhor e não consegui encontrar uma, então montei isso:

dd if=2031_20160514030000.mpg |
pv --size 4653819304 |
ssh -C -c arcfour,blowfish-cbc -p 5555 myserver.com 'dd of=/media/TV/2031_20160514030000.mpg'

Então, o que isso faz?

Primeiro, eu uso o dd para copiar o arquivo à medida que ele cresce. Como o arquivo cresce mais rapidamente do que o dd pode enviá-lo pela rede, o dd nunca alcança o final do arquivo. Em seguida, eu o canalizo para "pipe viewer (pv)" e faço uma estimativa do tamanho do arquivo, com base no tamanho desses arquivos. Isso não é necessário, mas eu gosto de ver um medidor de progresso. Em seguida, canalizo o fluxo para minha conexão ssh. A conexão ssh usa -Cpara compactação (para reduzir a largura de banda da rede e tentar acelerar), -c arcfour,blowfish-cbcpara a criptografia mais barata (novamente para acelerar um pouco as coisas), o-pé para a minha porta de firewall que estou usando no destino e o ssh finalmente executa o comando dd no destino para recriar o arquivo à medida que o recebe. Fico feliz em dizer que esta solução funciona muito bem. Eu posso assistir ao jogo de hóquei enquanto o arquivo está sendo criado e copiado com apenas um pequeno atraso.

Neophraz
fonte
0

Não tenho certeza de que o método tail -f funcione (embora provavelmente funcione se o arquivo for texto). O motivo é que eu não sei como tail -f e sftp transferem e confiam nas meta-informações.

Se o sftp transferir primeiro as metainformações e o tail -f confiar nas metainformações para informar que não há mais arquivos, o tail poderá prejudicar o final com EOFs ou nulos.

Se você não se importa com o caminho do upload, ou seja, o computador 1 carrega no computador 2 carrega no computador 3, tente usar o bittorent, em vez do sftp. Parece que foi para isso que foi projetado.

HandyGandy
fonte
0

Você pode tentar ler o arquivo desde o início, mas precisa ter certeza de que pode gravá-lo com a mesma velocidade, pelo menos.

Tim Connor
fonte