BashでTCPサーバーを作成する

BashでTCPサーバーを作成する

それで、最近ファイルを介してTCPパケットを送信する方法を見つけましたが/dev/tcp/hostname/port、最大の問題はそれをどのように受け取るかです。 TCPサーバーをホストできるbashスクリプトとTCPクライアントとして機能する別のスクリプトを作成したいと思います。少しの助けが良いでしょう。私もこれを学習経験にしていることを指摘したいと思います。これが私が望むことをする方法としてsshまたはを使用しない理由です。telnet

答え1

~によるとこれ、いいえ。bash試していないのでできません。bind(2)ソケットですが、試してみてください。connect(2)

netcatサーバーを起動するいくつかの方法は次のとおりです。

(私は使うnmap~のncatなぜなら牛に似た一種の栄養nc2004年以降のアップデートを見たことがない)


local $ :|{  ncat -l 9999 --keep-open --allow localhost |
local >      PS1='ncat $ '  PS2='ncat > ' dash +m -i 2>&1
local >   }  1<>/dev/fd/0
[1] + Running  : | { ncat -l 9999 --keep-open --allow localhost | PS1='ncat $ ' PS2='ncat > ' dash +m -i 2>&1; } 1<>/dev/fd/0

最後の:|パイプを借りました。dashそこに書いてncat読んでください。:もちろん、nullコマンドには必要ないからです。時にはそれよりも簡単ですmkfifo

とにかく、ポイントは、作成されたすべてのコンテンツがstdinにパイプさncatれ、作成されたすべてのコンテンツがstdinにパイプされることです。わかりました、そうではありませんが修正します。ただし、少なくともこのオプションは知っておく必要があります。dashdashncatbash+m


local $ ncat localhost 9999
ncat $ echo $0 $$
dash 31231
ncat $ ls -l /dev/fd/[012]
lr-x------ 1 mikeserv mikeserv 64 Dec 11 23:28 /dev/fd/0 -> pipe:[3563412]
l-wx------ 1 mikeserv mikeserv 64 Dec 11 23:28 /dev/fd/1 -> pipe:[3567682]
l-wx------ 1 mikeserv mikeserv 64 Dec 11 23:28 /dev/fd/2 -> pipe:[3567682]
ncat $ ^C
local $ 

+m通常、デフォルトで対話型シェルが開くように設定されている監視対象のジョブ制御シェルが制御-m端末-iからデータを読み取ろうとし、デフォルトでSIGTTIN自動的に一時停止するか、そうでない場合(無視またはブロックしようとする場合)殺す。


[1] + Stopped(SIGTTIN) : | { ncat -l 9999 | dash -i 2>&1; } 1<>/dev/fd/0

しかし、ここに端末はありません。出力からわかるようにパイプだけであるlsため、-mモニタリングは不可能です。

bash結局のところ、初期の対話型端末接続は無効になってもあまり柔軟ではないようですreadline


[1] + Stopped(SIGTTIN) : | { ncat -l 9999 | bash --noediting +m -i 2>&1 ; } 1<>/dev/fd/0

だから何をしますか?まあ、疑似端末が必要です。シミュレータにあるのと同じです。


local $ ls -l /dev/fd/[012]
lrwx------ 1 mikeserv mikeserv 64 Dec 11 23:30 /dev/fd/0 -> /dev/pts/0
lrwx------ 1 mikeserv mikeserv 64 Dec 11 23:30 /dev/fd/1 -> /dev/pts/0
lrwx------ 1 mikeserv mikeserv 64 Dec 11 23:30 /dev/fd/2 -> /dev/pts/0

/dev/ptmxLinuxシステムのマスターデバイスから1つを取得できます。tty(最初にグループのメンバーになりたくない場合は、ユーザーがグループのメンバーである必要があるかもしれませんchown。)。もし私たちが< open(2)ptmx デバイスは、次の場合に新しい疑似端末を生成します。unlockpt(3)読み書きできる新しいデバイスファイルです。

しばらく前に、私はシェルを使ってこれを行う簡単な方法がないことがわかりました。私はそれのために小さなCプログラムを書いた。。いくつかの説明と簡単な組み立て手順を確認できます。(実際にはシェルプロンプトにコピー/貼り付けるだけです)そのリンクから - これはpts私が以下で使用するプログラムです。


local $ { 9>&- setsid -c -- bash <> "$({ pts && 
local >   >&9  ncat -l 9999 -k --allow localhost
local > } <&9  &)" 2>&0 >&2 ; } 9<> /dev/ptmx
local $

bash開始がある会議の主催者擬似端末で標準出力のロックを解除し、名前を付けます。リダイレクトの標準をpts置き換えます。しかし、すべてのI / Oは別の場所(新しい疑似端末)であり、唯一のリンクはポート9999で始まったサーバーにあるため、何も起こらないようです。ここでは対話型スイッチは必要ありません。自動的に独自のLtd.になります。<>bashncat-ibash


local $ ncat localhost 9999
[mikeserv@desktop ~]$ echo hey
echo hey
hey
[mikeserv@desktop ~]$ ls -l /dev/fd/[012]
ls -l /dev/fd/[012]
lrwx------ 1 mikeserv mikeserv 64 Dec 12 00:27 /dev/fd/0 -> /dev/pts/4
lrwx------ 1 mikeserv mikeserv 64 Dec 12 00:27 /dev/fd/1 -> /dev/pts/4
lrwx------ 1 mikeserv mikeserv 64 Dec 12 00:27 /dev/fd/2 -> /dev/pts/4
[mikeserv@desktop ~]$ ^[[A^[[A

今はほぼすべて来ました。したがって、私たちは間違いなくソケットをbash持っていますが、そこには奇妙な二重エコーがあることがわかります。ここで問題は、2つのレベルの疑似端末があることです。私のクライアントが実行している擬似端末は、サーバーが実行されている擬似端末と同じにncat設定されています。stty echoそしてクライアントターミナルはライン指向であり、入力改行ごとに一度だけ出力をフラッシュし、デフォルト設定に応じstty echoctlてctrl-charエスケープも印刷するので、bash^ up矢印キーはまったく受信されず、面白いLittleエスケープだけを見ることができます。

わかりました、私たちもこの問題を処理できます。


local $ ncatsh()(
local >    ${2+":"} set  localhost "${1:?ncatsh(): No port number provided!}"
local >    stty="   stty -F'$(tty)'" || unset stty
local >    trap " ${stty- ncat '${1##*\'*}' '${2##*\'*}' </dev/null} \
local >           ${stty+$(for a in -g 'raw -echo isig intr "^A" quit "" susp ""'
local >                    do  eval "$stty $a";done)}
local >             trap - 0 1 2; exit"    0 1 2
local >    ncat  "$@"
local > )

この関数は標準入力が端末(ローカル端末)であることを確認し、そうでない場合は入力をクライアントに渡しますncat。しかしtrap、もしそうなら出口壊す邪魔する信号は終了時に標準端子状態を再開します。これもいいことだから。変化ncat標準を呼び出す前の状態です。

ローカルエコーが無効になっています。それ以外の場合、ローカル端末は次のように設定されます。生のモード - すべてのキーを押すとncatすぐにサーバーに送信されます。実際、すべての特殊ローカルモードキーは無効になります。とは別に地元の整数- 通常CTRL+Cしかし、ここの構成は次のとおりです。CTRL+A逆に - なぜならCTRL+Cbashサーバーから解釈されます。

またやりたいのですがls^上矢印を押してください。RETURN


local $ ncatsh 9999

[mikeserv@desktop ~]$ ls -l /dev/fd/[012]
lrwx------ 1 mikeserv mikeserv 64 Dec 12 01:00 /dev/fd/0 -> /dev/pts/4
lrwx------ 1 mikeserv mikeserv 64 Dec 12 01:00 /dev/fd/1 -> /dev/pts/4
lrwx------ 1 mikeserv mikeserv 64 Dec 12 01:00 /dev/fd/2 -> /dev/pts/4
[mikeserv@desktop ~]$ ^C
[mikeserv@desktop ~]$ ^C
[mikeserv@desktop ~]$ ^C
[mikeserv@desktop ~]$
local $

押すとローカルエコーがオフになるので、そこは見えませんでした。CTRL+Aセッションを中断し、すべてのローカル端末設定が正しい状態に復元されたローカルプロンプトに戻ります。しかし、サーバーはbashまだそこにありncatsh 9999、私が選択したらすぐに戻ってくるでしょう。

答え2

作業を簡素化するには、「netcat」ツールを試してください。サーバーまたはクライアントとして使用でき、任意のデータを送受信できます。

もしそうなら、低レベルのものを扱うことに気を付けないでください。

#server listening on port 8000/tcp
$>netcat -l 8000

#client sending stuff to localhost 8000/tcp
$>netcat localhost 8000
blah

答え3

bash仮想/dev/tcp/host/portファイル(元のksh関数)は、次の場合にのみ使用できます。つながるTCPポートソケット。

リスニングソケットを作成し、それから受け入れソケットを作成するなど、より多くのことをしたい場合は、リダイレクトを使用して実行することはできません。

zshzsh/net/tcpモジュールと組み込み機能によりこれをサポートしますztcp

zmodload zsh/net/tcp
handle-connection() (
  IFS= read -ru4 line || exit
  print -r "Got: $line"
  print -ru4 "Hello $line"
  ztcp -c 4
)

ztcp -l -d 3 1234 # create a TCP listening socket on port 1234 on fd 3
while ztcp -ad4 3 # accept connection on fd 4
do handle-connection & exec 4>&-
done

バインドするアドレスまたはリスニングキューのサイズを指定できない、1方向だけをオフにする、またはソケットオプションを設定できないという点で依然として制限されています。 UDPまたはSCTPも実行しません(できます)。コマンドを使用しますが、Unixドメインソケットインタフェースzsocket)。

より高度な機能が必要な場合、またはzshがない場合socatbash

handle_connection() {
  IFS= read -r line &&
    printf 'Hello %s\n' "$line"
}
export -f handle_connection
socat tcp-listen:1234,reuseaddr,fork 'exec:bash -c handle_connection'

可能性はsocat無関心です。詳しくはマニュアルページをご覧ください。

たとえば、サーバーにシェルセッションを作成させるには、次のようにします。

socat tcp-listen:1234,reuseaddr,fork exec:bash,pty,ctty,setsid,stderr,sane

クライアント側では、次のように接続できます。

socat -,raw,echo=0 tcp:host:1234

答え4

最も簡単な方法は、xinetd次のように独自のサービスを作成することです。

/etc/services:

...
foo             500/tcp
...

/etc/xinetd.d/foo:

service foo
{
        disable         = no
        bind            = 127.0.0.1
        socket_type     = stream
        protocol        = tcp
        log_on_failure += USERID
        server          = /usr/local/lib/foo.sh
        user            = il
        instances       = UNLIMITED
        wait            = no
        log_on_success  =
}

/usr/local/lib/foo.sh:

read ...
...
echo ...

したがって、シェルスクリプトは各クライアント接続に対して実行され、stdin / stdoutをソケットに直接追加します。

関連情報