ネットワーク越しでパイプしたり、あらゆるデバイス間でデータ転送したい！

## 何を解決したいか？

Mac, Windows, Linux, iPhoneやAndroidのスマホ・タブレットとかのデバイス間でデータの転送したいことがあります。

SlackとかLineとかSkypeとかAirDropとかあっても　

* 送りたい相手と共通して使っているサービスを探す必要とか、
* GUIのソフトウェアのインストールが必要とか、
* AirDropだとApple系OSである必要

があるなどの転送の障壁があって、GUIが使えないデバイスに送りたいときなどは困ってしまいます。
すでにたくさんのファイル共有系のサービスがありますが、コマンドを使ったCUIベースにあまり親切な設計なものはあまりないと思います。

そこで、上記の問題を解決するために、以下のようなファイル転送の仕組みを作りました。

* **他デバイス間でデータ転送**ができ、
* 別途ソフトウェアの**インストール不要**で、
* パイプにとても親和性が高く**エンジニアフレンドリー**

## 実際の動作

データの送信者も受信者も転送するためにインストールするものはありません。
curlコマンドやブラウザなどHTTP通信ができるものがあれば転送できます。
以下のデモでは、`seq 100000`を上のマシンから下のマシンに送っています。

![opt.gif](https://qiita-image-store.s3.amazonaws.com/0/84451/7cd645fb-510e-6b0e-07c9-3a81a72c3b72.gif)

これは`seq 100000`以外にも`cat`でも`ls`でもパイプ渡せるあらゆるものが転送できます。例えば、ファイルが送りたいときは`cat ファイル名`とします。
以下のように、`100MB.dat`をデバイスをまたいで送れます。
![opt.gif](https://qiita-image-store.s3.amazonaws.com/0/84451/a0321284-9a33-aead-f001-fa8406b38fe2.gif)

エンドツーエンドの暗号化なども可能です。
パイプが使えるということは、圧縮や暗号化など、また２つ組み合わせて圧縮+暗号化すること可能です。
圧縮送信: `cat myfile | gzip | curl -T ...`
解凍受信: `curl ... | zcat > myfile`
や
暗号化送信（共通鍵）: `cat myfile | openssl aes-256-cbc | curl -T ...`
復号化受信（共通鍵）： `curl ... | openssl aes-256-cbc -d > myfile`

暗号化に`gpg`を使ってもいいですし、将来の最新の暗号方式や圧縮方式が出たらそれを使うことも可能です。
一時的なファイルも経由せず、時間的にも空間的にも効率が良く、パイプの素晴らしい可能性が発揮できます。
他にもパイプを使った便利なデータ転送を後述します。

- - -

最小の転送機能を搭載したWeb Clientでもファイルを送ったり受け取ったりすることが可能です。
IE10やIE11でも動作可能でした。
以下のデモのようにターミナルからブラウザに画像ファイルを送ることも簡単です。
![opt.gif](https://qiita-image-store.s3.amazonaws.com/0/84451/91940df6-762e-1c50-ed21-5eed22fef29c.gif)


以下のようにブラウザからもファイルを送ることができ、`curl`で受け取れます。
![opt.gif](https://qiita-image-store.s3.amazonaws.com/0/84451/f19e53f1-a6c0-1c82-ff11-27ba8e20865c.gif)
追記: もう少しリッチなWeb UIができました:
「[Web上でファイル転送をスマホでもPCでもcurlでも手軽にしたい！ - Qiita](https://qiita.com/nwtgck/items/2dd47031ba729256f5eb)」

まとめると、

* 従来のHTTP通信で転送可能
    * 成熟した枯れた技術に支えられている
* データはストリーミングされる
    * Unix/Linuxなどのパイプで効率よく転送できる
    * サーバーはデータを経由させるだけで保存は一切しない
    * Stream APIの力でうまいこと背圧制御とかもされる

です。

---
追記（2019/02/13）
@Cryolite さんによって、Piping Serverを使って任意のネットワークコネクションを確率する手法が発案されました。具体例では、外向きTCP80ポートの許可のみでssh接続が可能なことが示されています。以下の記事にて原理について詳しく紹介されています。
[Piping Server を介した双方向パイプによる，任意のネットワークコネクションの確立 - Qiita](https://qiita.com/Cryolite/items/ed8fa237dd8eab54ef2f)

---

## GitHubリポジトリ

プロジェクトは**Piping Server**と呼んでます。デバイス間のデータをネットワーク越しでパイプさせたい思いをこめました。
サーバーサイドTypeScriptです。

GitHub: https://github.com/nwtgck/piping-server


## サーバー

どこかのサーバーが独占するわけではなく、サーバーは自由にたくさん立てるポリシーです。好きに自分用のサーバーを立ていただければと思います。デモ用にいくつかサーバーを立てました。 [^public_server_may_shutdown]


 * <https://ppng.io/>
 * <https://piping.glitch.me/>
 * <https://ppng.herokuapp.com/>
 * <https://piping-47q675ro2guv.runkit.sh/>


オススメは<https://ppng.io>です。この中で一番短いのでコマンドのタイプ数を削減できます。

その他個人的な運用では、LAN内にPiping Serverを立ててLANではより高速かつ閉じた転送するのに使ってます。主にLAN内ではSSHなどが使えない場合、特にLinux<=>Windowsなどで使ってます。


使い方が忘れたときはGET /helpで簡単にヘルプが確認できます。

```bash
$ curl https://ppng.io/help
ヘルプが出力される
```


サーバーの立てやすさもこだわっていて、

* ポータブルなバイナリで起動させたり、
* `docker run`で起動できたり、

自分用のサーバーを手軽に立てれるようにしてます。サーバーの立て方は、下の方に書きたいと思います。

## データ転送の仕組み

HTTPを使います。また、NAT超え問題を解決するために、サーバーが送信者と受信者の経由役になります。おそらくピアツーピア(P2P)のTURNサーバに似たものだと思います。

多くのデバイス・OSでの利用できるようにするためとインストール不要を実現するために、
広く広まっているプロトコルでの通信が不可欠です。そこで通信はHTTP/HTTPSを使います。

CUIからは、`curl`や`wget`で簡単にデータを送るのも、受け取るのも可能です。`curl`や`wget`は最初からインストールされている事が多いです。
macOS, Ubuntu, Amazon Linuxなどよく使われているOSには最初から入っています。
Windows も Windows 10 version 1803 から標準で`curl`コマンドが入るようになりました。
しかも`curl`は広く使わていて枯れた技術であり、とても信頼できます。

HTTPを使っているため、GUIでもブラウザからデータを送ることも受け取ることもです。
ブラウザならMacでもWindowsでもiPhoneやAndroidなどのスマホ・タブレットでも使えます。


送受信は手軽行えるように極限まで**シンプル**にしました。

* 送り方は、任意のパスを指定して、**POSTかPUTのボディに送りたいデータを付けて送る**だけです。
* 受け取り方は、**そのパスを指定してGET**すればダウンロードできます。

セキュリティのために、データはサーバ上に保存せず、**ストリーミングされて転送**されます。
このストリーミングのおかげでUnix/Linuxのパイプと親和性が高く、効率よく、大きなデータの転送が可能になりました。


## セキュリティ

セキュリティに関してはデータ転送においてとても重要なところです。

まず、HTTPSを使っていれば、**クライアント<=>サーバー間は暗号化**されます
上記に書いた`openssl ...`や`gpg`コマンドなどを使えば、**エンドツーエンドの暗号化も可能**になり更に安全になります。


上で紹介したデモ動画だと、「送信者がPOST/PUTしたあと、受信者がGET」という順序ですが、**「受信者がGET、送信者がPOST/PUT」の順序でも**送信できます。後者のほうがよりセキュリティ的には良いと思います。
理由としては前者だとの方法だと、送信者が先に送る準備をしてしまうため、真の受信者がGETする前に、他の受信者がそのパスを指定しまうと、データを得れるからです。もちろんパスを十分に推測不能なものにすればいいのですが、その状況を防げる**GET firstがより安全**です。

パスは早いものが勝ちになるので、以下のように既に受信者がいる場合は拒否されます。たまたま、ぶつかる可能性があるときも先にGETして予約していたほうが、送信者との安全なコネクションがはれると思います。

1. GET  /mydata => 送信者を待つ
1. GET  /mydata => 拒否されて接続が切断　（すでに待ち状態の人がいるから） 
1. POST /mydata => 1の人に転送される


以下は、より安全なGET firstでの転送の様子です。
![opt.gif](https://qiita-image-store.s3.amazonaws.com/0/84451/d24cf1cd-ea2e-85f8-8d8f-4c20561e1b9a.gif)

## 複数人に送信

`/mypath?n=3`のように受信者の人数を指定できる機能があります。`n`を指定しないときは`n=1`になるようになっていて、今までは`n=1`で転送されていました。

サーバーに保存されないため、一度ストリームが流れてしまうと同じデータを受け取りたい人に送るときの効率が悪いです。それを解決するための機能になってます。
<img src="https://qiita-image-store.s3.amazonaws.com/0/84451/b3c85169-64e5-27c2-1575-9e8cd8490bd4.gif" width="450">

### 複数人に送るときのセキュリティ

`n=3`のときは、4人目が受信しようとした時点で、4人目の接続が拒否され切断されます。つまり、`n`を指定しない`n=1`のときは2人目受信しようとした時点で2人目の接続が拒否され切断されます。`n`を一般化しているだけなので、上記の通りGET firstなコネクションがより安全な転送方法になると思います。

### 複数人に送る技術的な話


データの元のストリームがあってそれを複数に分配するような仕組みが必要です。イメージ的には以下の図のようになります。

```
                    ----------> HTTP GET 受信者1
                    |
送信者 HTTP POST ---サーバー-----> HTTP GET 受信者2
                    |
                    |
                    ...
                    ----------> HTTP GET 受信者N
```

サイバーサイドTypeScriptなので、Node.jsを使っています。
[stream.PassThrough](https://nodejs.org/api/stream.html#stream_class_stream_passthrough)を使って実現が可能です。

StackOverflowに短い例があったので、引用させていただきます。
下の例だと`echo hi user`の出力の文字数をカウントしつつ、出力の文字列自体も表示しています。

```js
const spawn = require('child_process').spawn;
const PassThrough = require('stream').PassThrough;

const a = spawn('echo', ['hi user']);
const b = new PassThrough();
const c = new PassThrough();

a.stdout.pipe(b);
a.stdout.pipe(c);

let count = 0;
b.on('data', function (chunk) {
  count += chunk.length;
});
b.on('end', function () {
  console.log(count);
  c.pipe(process.stdout);
});
```

```:出力
8
hi user
```

ソース：[javascript - Node.js Piping the same readable stream into multiple (writable) targets - Stack Overflow](https://stackoverflow.com/a/19561718/2885946)

`new PassThough()`を作って、そのPassThoughを最初に.pipe()させて、もとのストリームではなくPassThoughのメソッドの.on()や.pipe()を使って処理をしているのが分かると思います。

HTTPサーバーを作るときの`http.IncomingMessage`や`http.ServerResponse`でも同じように使えます。
実際にPiping ServerでのPassThoughを使っている箇所は以下になります。
https://github.com/nwtgck/piping-server/blob/eb40fe251b2a552348a4f8f8e635529460f2b4fa/src/piping.ts#L299-L362

## Piping Serverの立て方

すぐに気軽に立てれるように、いくつかサーバ立てる方法を用意しています。

### Herokuに立てる

Herokuに立てる方法についてです。
以下のPiping Serverのリポジトリにある紫色の[Deploy to Heroku]を押すと、手軽にデプロイできます。
GitHub: <https://github.com/nwtgck/piping-server>


### ボータブルなバイナリ実行形式

[zeit/pkg](https://github.com/zeit/pkg)を使って、npmで管理されているプロジェクトをポータブルなバイナリしています。
`node`本体とソースコードを含めることで`node`をインストール不要で動かせるようになっています。

以下のコマンドで、ダウンロードして、実行権限を与えて <http://localhost:8888>にPiping Serverが立ち上がります。

```bash
wget https://github.com/nwtgck/piping-server-pkg/releases/download/v0.8.4/piping-server-macos
chmod +x piping-server-macos
./piping-server-macos --http-port=8888
```

環境を汚さないのと導入が手軽なのがメリットです。
`...-alpine`、`...-macos`、`...-linux`と`...-win.exe`が[GitHub release](https://github.com/nwtgck/piping-server-pkg/releases)にあります。gitのタグがつくとCI上で自動で[GitHub release](https://github.com/nwtgck/piping-server-pkg/releases)ビルドしたバイナリをデプロイするように自動化しました。現在はPiping Serverと別リポジトリですが、将来はマージされる可能性があります。

### Docker

以下の`docker run`で、バックグラウンドで動作しマシンの再起動後も自動起動で<http://localhost:8888>にPiping Serverが立ち上がります。

```bash
docker run -d --restart=always -p 8888:80 nwtgck/piping-server --http-port=80
```

Alpineベースのイメージのためそこそこ軽量です。[![](https://images.microbadger.com/badges/image/nwtgck/piping-server.svg)](https://microbadger.com/images/nwtgck/piping-server "Get your own image badge on microbadger.com")

Piping Serverはデータを保存しないので、`-v`での永続化もデータベースに繋ぐ必要もありません。
Docker imageもgitのタグがつくと、Docker automated buildで自動でイメージがビルドされるようになっています。

### npm

Piping Serverはnpmのパッケージなので、以下のようにインストールすることができます。

```bash:インストール
npm install -g piping-server
```

以下のように起動させると、<http://localhost:8888>にPiping Serverが立ち上がります。

```:起動
piping-server --http-port=8888
```

これもgitのタグがつくと自動で、npm publishされるようにCIで自動化して人為ミスなどを減らしています。

### npx

`npx`を使えば以下のように起動できます。

```
npx piping-server --http-port=8888
```


### Docker(`bytenode`)

これは実験的なプロジェクトです。
[bytenode](https://github.com/OsamaAbbas/bytenode)というJavaScriptをGoogle V8のバイトコードに事前にコンパイルしてそれを実行するプロジェクトがあり、それを利用したDocker imageです。メリットとしてはDocker imageが軽量です。

webpackなどの代替の[parcel](https://github.com/parcel-bundler/parcel)を使って、bundleして、それをバイトコードしてそれだけでalpineベースのDocker imageに乗せているので、より軽量なイメージになっています。

これも実験的なので別リポジトリです。
<https://github.com/nwtgck/bytenode-piping-server>

イメージ名以外起動方法が変わりませんが、イメージサイズがより軽量です。 [![](https://images.microbadger.com/badges/image/nwtgck/bytenode-piping-server.svg)](https://microbadger.com/images/nwtgck/bytenode-piping-server "Get your own image badge on microbadger.com")

```bash
docker run -d 8888:80 nwtgck/bytenode-piping-server --http-port=80
```

現在実験的なプロジェクトです。ある程度使ってみて安定してそうだったら、本家のイメージもこの方法で作るようになるかもしれません。

### HTTPでのデータ転送の可能性

「HTTPってどこまで大きいファイル送れるの？」 「HTMLとかRESTのAPIサーバーとか小さいデータを返すイメージしかない」という疑問に関してです。
Piping Serverで無限にデータを送り続ける実験を47日前に開始しました。現在も進行中で、その結果では現在**868テラバイトのデータが転送**できています。

無限に送るのは単純で`/dev/urandom`をcatしているだけです。

```bash:無限に送る送信者
cat /dev/urandom | curl -T - localhost:8888/rand
```


```bash:無限に捨てる受信者
curl localhost:8888/rand > /dev/null
```

この結果から少なくともlocalhostなら868テラバイトは転送できることが体感できました。

## `curl -T　-`とは

この記事でよく登場している`curl -T - ...`はPUTメソッドで、標準入力（=パイプされたもの）をHTTPのボディにつけて送ってくれるオプションです。`-T`==`--upload-file`です。
`-`を使わずに`curl -T ファイルパス ...`の場合は指定されたファイルを送ることができます。

PUTではなくPOSTを使いたいときは、以下でもできます。ただPiping ServerではタイプしやすいようにPUTに対応してます。
`cat myfile | curl --data-binary @- https://ppng.io/mydata`

## パフォーマンス比較 - Go言語との比較

オリジナルの実装がTypeScript/Node.jsです。そこで、Go言語で最小限のPiping Serverを実装して転送速度の比較をしました。転送にかかる時間は大きく差があればあるほど、アップロード・ダウンロードともにユーザー体験が損なわれるので、調べました。比較対象としてGoを選んだのは、新しいサービスがGoで書かれていることが多くGoとの比較に興味があったのと、ネイティブな実行形式を作り出せるGoとスクリプト言語のJavaScriptでどれだけ差があるか知りたかったからです。

比較と言っても、そこまできっちりしたベンチーマークとかではなく、実際に送ってみて何MB/secか目視で確認する感じです。**結果的にはそこまで顕著な差で出なさそう**なことが分かりました。動画として結果を記録しました。

**TypeScript/Node.js**
YouTube: <https://youtu.be/ufijpqHlJww>
(<https://github.com/nwtgck/piping-server>)

**Go言語**
YouTube: <https://youtu.be/NuKvDwB9JSU>
(<https://github.com/nwtgck/go-piping-server>)

クライアントは無限に`yes`で`y`をlocalhostのPiping Serverに流し込みます。クライアントは送信者と受信者の組が3で、少しずつ増やしていきました。少しずつ増やしていくと、速度が41~42MB/s=> 38MB/s=>32~34MB/s のように変化する感じで、Node.jsもGoもだいたい同じくらいの速度でした。Node.jsはスクリプト言語ですが、データ転送部分で使ってる`ReadableStream#pipe()`の裏の実装がC++とかで書かれてて早いのかと勝手に推測してます。C++でのpipeの実装はこれかもしれません -> ([node/src/stream_pipe.cc](https://github.com/nodejs/node/blob/16362cb86801724dcc86f85fb51e550d482ee30d/src/stream_pipe.cc))


## パイプを活かした使用例

よく使いそうな例をまとめます。
パイプの可能性が発揮できそうな面白いものも後ろの方にまとめました。

### gzip圧縮して送る

`gzip`, `zcat`で圧縮送信、解凍受信可能です。

```bash:送る
echo hello | gzip | curl -T -  https://ppng.io/mymsg
````

```bash:受けとる
curl https://ppng.io/mymsg | zcat
````

### 暗号化して送る

`openssl aes-256-cbc`を使うとパスワードを使って共通鍵暗号方式でエンドツーエンドの暗号化が実現できます。

```bash:送る
echo hello | openssl aes-256-cbc | curl -T - https://ppng.io/mymsg
```

```bash:受けとる
curl https://ppng.io/mymsg | openssl aes-256-cbc -d
```

### ディレクトリを送る

ポイントは、以下のどちらのコマンドも一時ファイルを作らずにストリームでzipやtar.gzを作って、ディレクトリを転送できるところです。

```bash:zipで送る
zip -q -r - ./mydir | curl -T - https://ppng.io/mydir.zip
```


```bash:tar.gzで送る
tar zfcp - ./mydir | curl -T - https://ppng.io/mydir.tar.gz
```

## プログレスバーを出しながら送る

`pv`コマンドを使うと進捗のバーが出てくれます。
汎用的な方法は、以下のようにパイプとパイプの間に挟むことで進捗がわかります。
`... | pv | curl -T - ...`
![opt.gif](https://qiita-image-store.s3.amazonaws.com/0/84451/a43933e1-fb15-81d6-e366-5a04544d215f.gif)


ファイルを送りたいときは、以下のように`cat`の代わりに`pv`を使うことでOO/100%の形でバーが見やすくなります。
![opt.gif](https://qiita-image-store.s3.amazonaws.com/0/84451/a43f89c2-77c4-eb77-1f1c-cb4a918d6235.gif)

## WindowsでもCUIで転送したい！

PowerShellを使う方法の紹介です。
PowerShellは以下のアイコンのやつです。コマンドプロンプトとは別のアプリケーションで、少なくともWindows 10なら標準で入っているはずです。
![PowerShell icon](https://qiita-image-store.s3.amazonaws.com/0/84451/3a97a25d-07d9-350d-eae6-6048502db85c.png)


`iwr`コマンド(=`Invoke-WebRequest`標準のエイリアスのはずです)を使うとある程度`curl`の代わりになります。

```powershell:./mydata.datを送る
iwr https://ppng.io/mydata -InFile ./mydata.dat -Method Post
```

```powershell:./mydata.datとしてダウンロード
iwr https://ppng.io/mydata -OutFile mydata.dat
```

```powershell:パイプして送る
cat ./hello.txt | iwr -InFile $_ -Method POST https://ppng.io/mymsg
```

（PowerShellが使えなくても、ブラウザでファイルの送信・受信が可能です）

PowerShellはWindowsに限ったものではなく、マルチプラットフォームを目指しているようです。
個人的に一番お手軽に試せると思うのがDockerを使った方法です。
以下のコマンドでシェルが立ち上がります。

```bash
docker run -it microsoft/powershell
```

## vi系のエディタで送る

viやvimなどのエディタを使って一時ファイルを作らずにPiping Serverに送る方法です。

以下のように、`:w !curl -T - ...` で書いている内容を送ることができます。
![opt.gif](https://qiita-image-store.s3.amazonaws.com/0/84451/e5894c8d-0086-c9b2-15c3-b259130dc576.gif)

## 標準入力をリアルタイムに送る

以下のように、`cat | curl -T - ....`を使うと入力の内容が改行ごとに即時送られます。
![opt.gif](https://qiita-image-store.s3.amazonaws.com/0/84451/bab194c4-7d2f-d3b9-dbd9-33120da46a21.gif)
(追記： `-T -`で標準入力を受け取るので、`cat |`はなくてもOKですね。)

### ハッシュ値を計算しながら送る


送りながらハッシュ値を計算することで、より自信をもってデータを転送できます。
これのポイントも同じく、一時ファイルを作らずにストリーミングしながらハッシュ値を計算しているところです。

`>(shasum ...)`という記法はProcess Substitutionという機能で、bashやzshなどに搭載されています。

```bash:ハッシュを計算しながら送る
seq 100000 | tee >(shasum >&2) | curl -T - https://ppng.io/myseq
```


```bash:ハッシュを計算しながら受けとる
curl https://ppng.io/myseq | tee >(shasum >&2) > seq.txt
```

上記のコマンドを理解するためには、`tee`とProcess Substitutionの両方の知識が必要です。標準入力を`tee`は与えられたファイルに書き出しつつ、標準出力にも吐き出します。
`>(shasum >&2)`を使うと`shasum`の標準入力の部分がファイルになってくれてるイメージで、以下のように`echo`すると雰囲気がだいたいつかめると思います。

```bash
$ echo >(shasum >&2)
/dev/fd/63
```

`>(shasum >&2)`で`shasum`の標準入力へのファイルパスが得られるため、`tee`でうまく動くという感じだと理解しています。



## 動画をストリーミングで見たい


以下のようにmp4の動画をPiping Serverに送って、ブラウザで開けば簡易的なストリーミングで動画が視聴できます。

```bash
 cat ray.mp4 | pv | curl -T - -H 'Content-Type: video/mp4' https://ppng.io/myvideo
```
![Piping Video Streaming](https://qiita-image-store.s3.amazonaws.com/0/84451/1ec5112e-aedb-832b-d127-dae8e444888c.gif)

ポイントは、すべての動画がダウンロードされる前から、再生されているところです。簡易的なストリーミングできています。
これに対応したmp4を作成するには、プログレッシブダウンロードに対応させる必要があります。
以下のコマンドで`input.mp4`からプログレッシブダウンロード対応の`output.mp4`を生成できます。

```bash
ffmpeg -i input.mp4 -codec copy -movflags faststart output.mp4
```

参考： [プログレッシブダウンロード対応の MP4ファイル を作成する :Tips & FAQ - arbk-works](https://aruo.net/arbk/blog/article/techclip_how2make_mp4_video_file_for_progressive_download_with_ffmpeg_or_mp4box)


## ターミナルの画面を共有する！！

`script`コマンドと`curl`があれば、ターミナルの画面共有も可能です！

共有したい画面の人は以下のコマンドをたたきます。

```bash:画面を共有したい人
script -f >(curl -T - https://ppng.io/myscript >&/dev/null)
```
(Macの場合は`script -f`の代わりに`script -F`)

```bash:共有された画面を見る人
curl https://ppng.io/myscript
```

`/myscript`の箇所は適宜変えて使ってください。
仕組みとしては、`script`コマンドというターミナル作業ログをとるコマンドの力です。
ログをファイルに取れて、Process Substitution`>(curl -T -)`に向かってログするようにしています。ネットワーク越しにこれをパイプできるPiping Serverに渡るため、画面を見る人はただ`curl ...`するだけで画面を見ることができます。

以下がターミナル画面共有のデモです。
![opt.gif](https://qiita-image-store.s3.amazonaws.com/0/84451/c6563170-4f7d-9127-aba3-3997e2a61f09.gif)

魅力は既存のインストールされているであろう`script`コマンドと`curl`だけでターミナル共有が完結するところです。また、色のついた文字や`top`や`sl`など動きが激しい画面もうまく共有できています。`/myscript?n=3`などとすれば、3人に画面共有することもできます。


[^public_server_may_shutdown]: コマンドで完結するため、広告などでサーバー運営費をまかなえるようなサービスではないので、予告なしにサーバーと止めることがあると思います。サーバーは手軽にたてれるように心がけたので、止まってしまった時はご自身で立ていただければと思います。

## 【追記】 Piping Server使った他の色々
（追記：2019/03/23）

[Piping Server - @nwtgck/Ryo Ota](https://scrapbox.io/nwtgck/search/page?q=Piping%20Server)

上記ののリンク先で、

* HTTP/2対応
* GraalVM上での起動
* ロードバランサー対応
* 暗号通話
* ...

などについて書いてます。今後もPiping Serverの活用/応用など増えていくかもしれません。

## 【追記】 以前、似たもの作っていなかった？
（追記： 2019/02/07）

Piping Serverと同様にOver HTTP/HTTPSでファイル転送したい思いで以前に作っていました。

以下のQiita記事で紹介していた**Trans Server**というのを作っています。
**Qiita**: [標準コマンドだけでファイルを送りあえるサーバーを作ってみました - Qiita](https://qiita.com/nwtgck/items/63da1afabf92a665f610)
**GitHub**: https://github.com/nwtgck/trans-server-akka

Piping Serverと違って、**ストリーミングせずに後でダウンロードしたい**という要望を叶えるために作りました。
ほぼPiping Serverとインターフェースの部分は同じです。
違うところが、送信後にデータのIDが返されて、そのIDを使って好きなタイミングでダウンロードできるところです。
そのため、Piping Serverではできないデータ転送をしたいときに使っています。
ダウンロード回数制限や、一定時間での削除、IDを長くしてセキュリティの強化などの機能がついています。

技術はScala/Akka HTTP/Akka Streamなどを主に利用しています。

<!--
### `nc`, `echo`, `wc`, `bc`だけで送る

`curl`がインストールされていなく、
`nc`(netcat), `echo`, `wc`だけ送りたくなったときの方法です。


```bash:curlを使わずに送る
fpath=./myfile.txt; host=ppng.io; path=/mypath; (echo -e "POST $path HTTP/1.1\nHost: $host\nContent-Length: $(wc -c < $fpath | bc)\n"; cat $fpath) | nc $host 80
```
環境変数`fpath`, `host`, `path`を適宜変えてみてください。


### `echo`, `nc`, `awk`で受けとる

```bash:curlを使わずに受けとる
host=ppng.io; path=/mypath; echo -e "GET $path HTTP/1.1\nHost: $host\n\n" | nc $host 80 | awk -v h=1 '!h{print $0} /^\r?$/{h=0}'
```

環境変数 `host`, `path`を適宜変えてみてください。
-->