何を書きますか
前回の記事では、PHPで簡単なターミナルエミュレーターを作成しました。 今こそ、Webソケットについてもっと深刻なことを書くときだと思います。 Webソケットの操作に使用する言語は何ですか? Python ..? ルビー..? JavaScript ..? いや! Go 1が登場したので、書きましょう;)。 私はここで自分自身を繰り返さないで、コード全体を書かないようにします。 私の意見では、興味深い断片のみを提供します。
デモ
ターミナルエミュレータの動作を
見る機会を与えてくれた
Aleks_jaに感謝します(最新バージョンのWebソケット(Firefox 11や最新のChromeなど)が必要です)。 デーモンが100ミリ秒で起動する時間がない場合、初めて接続できない場合があります。最初にページを更新してみてください。
Webターミナルのソースコード
はgithubで入手できます。 (
go build
)Webソケットデーモンを自分でコンパイルする必要があります-これは、ホストを「クラック」するのを好む人に対する小さな保護策です。
成分
そのため、次のものが必要です。
- Goコンパイラ1がインストールされている
- Websocketライブラリ(code.google.com/p/go.net/websocketを
go get code.google.com/p/go.net/websocket
) - 最新のWebsocket仕様をサポートするブラウザー(最新のFirefoxおよびChromeなど)
- PHPを備えたWebサーバー(デーモンを自動的に起動するため)
Webデーモンソケットの作成
デーモンでは、Webソケットサーバーと擬似端末エミュレーターが組み合わされます。 Goで擬似端末を使用するためのネイティブサポートがないという事実にもかかわらず、この言語はCと簡単に統合されるため、Cの対応する呼び出しを使用して擬似端末を直接操作します。
Webソケットを操作する
package main import ( "code.google.com/p/go.net/websocket" "http" "log" )
擬似端末で作業する
forkpty()とioctl()のバインディングを記述します(ioctl()で端末の「ウィンドウ」のサイズを変更します):Goは、Cとうまく統合できますが、pid_tとintが同じものであることを理解しませんC関数で可変数のパラメーターを操作する方法がわかりません。
package main import "C"
ハンドラーでは、これを使用します。
func PtyServer(ws *websocket.Conn) { cols, rows := 80, 24
Webソケットと擬似端末間の通信
次に、たとえばbashを実行して、対応する記述子(pttyno)からの出力をWebソケットに送信する必要があります。逆も同様です。Webソケットから入力pttynoに入力を送信するのは簡単です。 この問題は、不完全なUTF-8シーケンスが疑似端末から届いたときに発生します。 擬似端末からはブロック(たとえば2 Kb)でのみ読み取ることができ、ブロックの終わりはUTF-8文字を2つの部分に「カット」できます。この「トリム」はブラウザーに送信しないでください。 この状況を正しく処理する小さなコードを次に示します。
for end = buflen - 1; end >= 0; end-- {
UTF-8文字(Goの用語-ルーン語)の先頭として機能するバッファー(buf)の最後のバイトを見つけて、この文字がそのままかどうかを確認する必要があります。 すべてが最後の文字で問題ない場合は、バッファーの「終了」を返します。それ以外の場合は、バッファーのサイズを縮小して、文字全体のみがそこに残るようにします。
疑似端末からの出力をブラウザーに表示します
最初は、JSLinuxを使用して出力を表示しましたが、その作成者はライブラリのコードの変更と配布を許可していません。そのため、
Selectelの仲間が書いた
selectel / pyteライブラリを使用しましょう。
Javascriptで書き換えます :)! pythonからの移植は完璧ではありません。また、私はpythonの特別な専門家ではありませんが、その仕事はします-Midnight Commanderが起動して問題なく動作します。
ユーザー入力を受け入れる
ユーザー入力を受け入れるために、JSLinuxの作成者から一定量のコードを借りました。基本的な原理は
ここで説明されています 。 また、下の入力フィールドにテキスト(パスワードなど)を挿入する機能を追加し、F1-F12キーとAlt +(左/右矢印)のマッピングを追加しました。 判明したように、Fキーの入力文字の値は環境変数$ TERMに依存し、VT100のキーボード上になかったため、vt100にはまったく定義されていません:)。 出力にはpyteが使用されるため、$ TERM環境変数はlinuxと等しくなければなりません。したがって、この端末ではこれらのキーのマッピングを使用します。
「オンデマンド」でデーモンを起動します
最後の接続の1分後に終了するようにWebソケットデーモンを実装したため、端末でページを開くときにスクリプト自体がWebソケットデーモンを起動すると便利です。 このためのPHPコードは非常に簡単です。
<?php $PORT = 13923;
exec
わからない場合は説明します。これはUNIXシェルの特別な組み込みコマンドであり、シェルを強制的に呼び出されたプロセスに置き換えます。 つまり、「余分な」プロセス
sh -c ./ws ...
はありません。
私が話さなかった瞬間
次の
実装の詳細については話しませんでした。
- クライアント通信プロトコルはウィンドウのサイズ変更をサポートするために少し複雑でした
が、ロシア文字の入力にバグが現れました - Webデーモンはパスワードで保護されており、起動時に自動的に生成され、接続時に使用されます
- bashrcを使用して、目的の端末設定を設定します
- サーバーにレンダリングがないため、バイトのみが送信されるため、デーモンはsshdに匹敵するサーバーをロードします(つまり、CPU負荷はゼロに近い)
- javascriptのpyte実装は非常に高速です。MidnightCommanderの起動時に目に見える遅延はありません。スループットは毎秒数千行のテキストです
- ブラウザウィンドウを閉じると、セッションは正しく終了します
- 1つのデーモンで多数のクライアントを問題なく同時に処理できます。
- <audio>タグとubuntuからの音の使用により、端末は「ビープ音」を鳴らすことができます:)
Githubプロジェクト
興味がある人のために、githubへのリンクを繰り返します:
github.com/YuriyNasretdinov/WebTerm-記事で説明したターミナルエミュレーター
github.com/YuriyNasretdinov/pyte-JavaScriptでのselectel / pyteライブラリの実装(残念ながら開発者には受け入れられません)