Pythonで作ってみました。
ポートを指定してサーバを1つ起動しておきます。
みんなでnetcat (ncコマンド) でつないでチャットします。
$ ./chat_conn.py <port> <port>: サーバのポート番号
$ nc <hostname> <port> <hostname>: サーバが起動してるホスト名 同じマシン上なら 'localhost' <port>: サーバのポート番号
ncコマンドでポートを指定してサーバにつなぎに行くと 'who?' と名前を聞かれます。
名前を入力すると、登録された名前が表示されます。
(同じ名前が既に存在したら、適当に修正されて登録されます)
例えば mac_a でポート番号 12345でサーバを起動。
mac_a $ ./chatt_conn.py 12345
同じ mac_a で foo さんが接続するとしたら
mac_a $ nc localhost 12345 who? foo foo
他のマシン mac_b から bar さんが接続するならば
mac_b $ nc mac_a 12345 who? bar bar
mac_a から、さらに別のbarさんが接続したならば
mac_a $ nc localhost 12345 who? bar bar_2
名前が重複しないように、適当に修正されて登録されます。
メッセージの内容 + 改行 を送信します。
メッセージ
送信したメッセージが、接続してる他のメンバーに送信されます。
他のメンバーには次の形式で表示されます。
送信者名> メッセージ
メッセージの前に @宛先名 + 空白 を付けると、その宛先のみに送られます。
@宛先名 メッセージ
メッセージの前に、複数の宛先を指定する事もできます。
@宛先名1 @宛先名2 メッセージ
@srv コマンド
の形式のメッセージを送信します。
コマンドは次の通り。
接続中のメンバーの名前一覧が表示されます。
(問い合わせた本人も含まれます)
@srv names foo bar foo_2 hoge_hoge
接続を解除して切断します。
exit, quit でも同様です。
@srv bye
サーバを終了させます。
接続中の他のメンバーには 'srv> shutdown' が表示された後、切断されます。
@srv kill
サーバに接続しにいく時に、ncコマンドに頼らずとも、chat_conn.py でも可能にしました。
$ cat v2.patch | patch -p1 $ ./chat_conn.py Usage: ./chat_conn.py <port> [conn [<user name>] [<hostname>]] conn: client mode user name: default "guest" hostname: default "localhost"
2つめの引数に conn を指定すると、クライアントとして動作します。
3つめの引数に who? に答えるときの名前を指定します。
(指定がなければ、デフォルトは guest)
4つめの引数に、ホスト名を指定します。
(指定がなければ、デフォルトは localhost)
サーバの起動はこれまで通り
$ ./chat_conn.py 12345
クライアントの接続は nc コマンドを使わずに
$ ./chat_conn.py 12345 conn foo
これで nc コマンド使った場合に who? に foo と答えて foo を受け取る所まで相当になります。
$ nc localhost 12345 who? foo foo
サーバに接続するクライアントの先にコマンドをつなけるようにしてみました。
$ cat v3.patch | patch -p1 $ ./chat_conn.py Usage: ./chat_conn.py <port> [conn [<user name>] [host=<hostname>] [cmd=<cmd>]] conn: client mode user name: default "guest" hostname: default "localhost"
cmd="..." でコマンドを指定します。
cmdが指定されていると、chatで受け取った文字列を、標準入力に与えてコマンドを実行します。
コマンドが標準出力に出した文字列を、chatで送信します。
例えば標準入力の内容をそのまま標準出力に出す、catコマンドを与えた場合
$ ./caht_conn.py <port> conn <user name> cmd=cat
みなさんのセリフをおうむ返しするだけの、うざい奴になります。
もうちょと便利なように、chatの文字列の末尾が "... >hoge" で終わってる場合だけ、おうむ返しさせてみます。
$ ./chat_conn.py <port> conn <user name> cmd="sed -ne 's/^.*> \(.*\) >hoge$/\1/p'"
ちょっとマシな奴になりました。
もちょっと便利に、計算してくれる calc くんにしてみます。
"bc -l" コマンドで計算させてみます。
$ ./chat_conn.py <port> conn calc cmd="sed -ne 's/^.*> \(.*\) >calc$/\1/p' | bc -l"
例えば bash なら?
$ ./chat_conn.py <port> conn bash cmd="sed -ne 's/^.*> \(.*\) >bash$/\1/p' | bash"
コマンドで指定するsedの切り出し呪文が面倒なので、専用の指定を追加してみました。
$ cat v4.patch | patch -p1 $ ./chat_conn.py Usage: ./chat_conn.py <port> [conn [<user name>] [host=<hostname>] \ [cmd=[me:]<cmd>]] conn: client mode user name: default "guest" hostname: default "localhost"
cmd="..." のコマンドが cmd="me:..." と "me:" で始まっていれば
sed -ne 's/^.*> \(.*\) >name$/\1/p'
の切り出し相当の動作になります。
例えば名前calcのときに、cmd="me:bc -l" と指定すると
送信元> xxx >calc
のメッセージだけに反応して、bc -l コマンドに xxx を入力し、その結果をメッセージで返します。
$ cat v5.patch | patch -p1
コマンドを指定した時は「毎回コマンドを起動して」 受信した文字列をコマンドに入力として与えて、 コマンドが返した出力文字列を送信してました。
コマンドは初めに1度だけ起動して、 コマンドの入出力を中継できるようにしてみます。
$ cat v6.patch | patch -p1 $ ./chat_conn.py Usage: ./chat_conn.py <port> [conn [<user name>] [host=<hostname>] \ [cmd=[cont:][me:]<cmd>]] conn: client mode user name: default "guest" hostname: default "localhost"
ちょっとcmd=の指定が、変な仕様になってしまいました。
cmd=cont:xxx で起動すると、最初にコマンドを起動します。(従来のように毎回、起動/終了しません)
cmd=cont:me:xxx としてme:つきで起動すると、これまで同様に文字列の末尾に ' >xxx' として、自分宛の指定があったときだけ反応します。
$ ./chat_conn.py 12345 & $ ./chat_conn.py 12345 conn calc cmd="cont:me:bc -l" & $ ./chat_conn.py 12345 conn bash cmd=cont:me:bash & $ ./chat_conn.py 12345 conn foo @srv names srv> calc bash foo 1+1 >calc calc> 2 expr 1 + 1 >bash bash> 2 @srv kill srv> shutdown srv> logout calc srv> logout bash $
賭場コマンドなるものを作って、チャットのメンバーとして繋いでみました。
30秒ごとに丁半博打を仕切ってくれます。
20回分の10分で終了します。
すみません。まだバグがありますね。
バグ修正してみました。
$ cat v7.patch | patch -p1
工事中