TCPソケットのチャット2019夏

Pythonで作ってみました。

ポートを指定してサーバを1つ起動しておきます。

みんなでnetcat (ncコマンド) でつないでチャットします。


chat_conn.py




サーバの起動

$ ./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 コマンド

の形式のメッセージを送信します。

コマンドは次の通り。

names

接続中のメンバーの名前一覧が表示されます。

(問い合わせた本人も含まれます)

@srv names
foo bar foo_2 hoge_hoge

bye

接続を解除して切断します。

exit, quit でも同様です。

@srv bye

kill

サーバを終了させます。

接続中の他のメンバーには 'srv> shutdown' が表示された後、切断されます。

@srv kill


クライアントとして起動 (バージョン2)

サーバに接続しにいく時に、ncコマンドに頼らずとも、chat_conn.py でも可能にしました。

v2.patch

$ 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


クライアントの先にコマンドをつなぐ (バージョン3)

サーバに接続するクライアントの先にコマンドをつなけるようにしてみました。

v3.patch

$ 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"


自分当て指定のメッセージに応えるコマンド (バージョン4)

コマンドで指定するsedの切り出し呪文が面倒なので、専用の指定を追加してみました。

v4.patch

$ 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 を入力し、その結果をメッセージで返します。


修正もれなおしときます (バージョン5)

v5.patch

$ cat v5.patch | patch -p1


コマンドを起動したままの場合も (バージョン6)

コマンドを指定した時は「毎回コマンドを起動して」 受信した文字列をコマンドに入力として与えて、 コマンドが返した出力文字列を送信してました。

コマンドは初めに1度だけ起動して、 コマンドの入出力を中継できるようにしてみます。

v6.patch

$ 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
$ 


賭場コマンド

賭場コマンドなるものを作って、チャットのメンバーとして繋いでみました。

toba.py

30秒ごとに丁半博打を仕切ってくれます。

20回分の10分で終了します。

すみません。まだバグがありますね。


賭場コマンドのバグ修正 (バージョン7)

バグ修正してみました。

v7.patch

$ cat v7.patch | patch -p1


工事中