SCTPという、TCPとUDPのよいとこ取りをしたようなプロトコルがある。「SCTP(ネットワーク通信)」に書いたとおり、echoサーバを作成したが、動作確認のためにクライアントが必要になった。
telnetなどのTCP用のツールは使えないので、クライアントのプログラムも作成したが、もっと簡単にためせるツールがないかと思っていたら、「socat」というコマンドを見つけた。
 netcat(nc)(「netcat - ネットワーク万能ツール」を参照)をさらに機能強化して、これでもかというくらいいろいろオプションが指定できるようになっている。
あろうことかnetcatでは封印されているコマンドの実行も可能になっている。

socatインストール

 Ubuntu10.10もFedora14もパッケージが用意されているので、aptやyumでインストール可能。

使用例

クライアント/サーバモデル

 netcatに書いたのと同様、クライアントの標準入力の入力内容を、サーバ側の標準出力に出力するには以下のようにする。
■サーバ側
$ socat TCP4-LISTEN:8080 STDOUT   <-- 8080で受け取った内容を標準出力へ
テストデータ    <-- クライアントで入力した内容が出力される。
■クライアント側
$ socat STDIN TCP4:localhost:8080  <-- 標準入力をlocalhostの8080ポートへ出力
テストデータ        <-- 入力内容
^C                  <-- Ctrl+Cで終了。コネクションが切れるので相手も終了する。
 上記のサーバだと、コネクションがきれるとsocatは終了してしまい、終了するとlistenポートがTIME_WAITになって再起動してもしばらくは同じポート番号にbindできない。
そのため、以下のように「fork」と「reuseaddr」をつけることで、コネクションがきれても終了せず、ポートの再利用が可能なサーバが起動できる。
$ socat TCP4-LISTEN:8080,fork,reuseaddr STDOUT
 なお、netcatは同時に1コネクションしかデータをやりとりできないが、socatは「fork」を指定することで、接続のたびにsocatが起動され、複数のコネクションを同時に扱うことができるようになる。

ファイル転送

 ファイル転送は、上記の例で標準入力を転送元ファイル、標準出力を転送先ファイルとすればよい。
 ファイルを指定するには、OPEN:<ファイル名>とする。デフォルトではファイルがないとエラーになるので、「create=<bool>」をつけている。
■サーバ側
$ ls outfile.txt         <-- ファイルがないことを確認。
ls: outfile.txtにアクセスできません: そのようなファイルやディレクトリはありません
$ socat TCP4-LISTEN:8081,fork,reuseaddr OPEN:outfile.txt,creat=1  <-- 受信内容をoutfile.txtをオープンして受信
^C            <-- 終了させる。(forkがなければ、クライアントの終了と共に終了する。)
$ cat outfile.txt
テストデータだよ。     <-- たしかに転送されている。
■クライアント側
$ cat infile.txt        
テストデータだよ。       <-- 入力ファイルの内容
$ socat OPEN:infile.txt TCP4:localhost:8081     <-- inifile.txtをオープンして内容を送信
$

echoサーバ

 以下のように出力を「SYSTEM:<コマンド>」とすると、コマンドを起動できる。(Hobbit版のnetcatの-eオプションと同じ)
 以下のようにするとechoサーバが簡単に作れる。
■サーバ側
$ socat TCP4-LISTEN:8081 SYSTEM:cat   <-- 受信内容がcatコマンドの入力となり、catの出力が送信元に出力される。
■クライアント側
$ socat STDIN TCP4:localhost:8081
echoされるよ             <-- 入力内容
echoされるよ             <-- サーバから出力された内容
サーバのcatの出力先のしくみいまいちよくわからないが、クライアントで入力を標準入力でなくファイルにすると、指定したファイルにcatの出力が追記された。
なので、クライアントの入力に対して出力される模様。

TCSPを使う。

 もともと、TCSP用のクライアントがほしくて探したツールなので、SCTPでechoサーバとクライアントをやってみる。
■サーバ側
$ socat SCTP4-LISTEN:8081 SYSTEM:cat   <-- 受信内容がcatコマンドの入力となり、catの出力が送信元に出力される。
■クライアント側
$ socat STDIN SCTP4-CONNECT:localhost:8081
echoされるよ             <-- 入力内容
echoされるよ             <-- サーバから出力された内容
 これで、自分が作ったSCTPのechoサーバとも通信できた。

 その他の例や、オプションの詳細はmanを見てください。以下のようにすると、使用可能なオプションが表示されます。
$ socat -h
socat by Gerhard Rieger - see www.dest-unreach.org
Usage:
socat [options] <bi-address> <bi-address>
  options:
     -V     print version and feature information to stdout, and exit
     -h|-?  print a help text describing command line options and addresses
     -hh    like -h, plus a list of all common address option names
     -hhh   like -hh, plus a list of all available address option names
     -d     increase verbosity (use up to 4 times; 2 are recommended)
     -D     analyze file descriptors before loop
     -ly[facility]  log to syslog, using facility (default is daemon)
     -lf<logfile>   log to file
     -ls            log to stderr (default if no other log)
     -lm[facility]  mixed log mode (stderr during initialization, then syslog)
     -lp<progname>  set the program name used for logging
     -lu            use microseconds for logging timestamps
     -lh            add hostname to log messages
     -v     verbose data traffic, text
     -x     verbose data traffic, hexadecimal
     -b<size_t>     set data buffer size (8192)
     -s     sloppy (continue on error)
     -t<timeout>    wait seconds before closing second channel
     -T<timeout>    total inactivity timeout in seconds
     -u     unidirectional mode (left to right)
     -U     unidirectional mode (right to left)
     -g     do not check option groups
     -L <lockfile>  try to obtain lock, or fail
     -W <lockfile>  try to obtain lock, or wait
     -4     prefer IPv4 if version is not explicitly specified
     -6     prefer IPv6 if version is not explicitly specified
  bi-address:
     pipe[,<opts>]	groups=FD,FIFO
     <single-address>!!<single-address>
     <single-address>
  single-address:
     <address-head>[,<opts>]
  address-head:
     abstract-client:<filename>	groups=FD,SOCKET,RETRY,UNIX
     abstract-connect:<filename>	groups=FD,SOCKET,RETRY,UNIX
     abstract-listen:<filename>	groups=FD,SOCKET,LISTEN,CHILD,RETRY,UNIX
     abstract-recv:<filename>	groups=FD,SOCKET,RETRY,UNIX
     abstract-recvfrom:<filename>	groups=FD,SOCKET,CHILD,RETRY,UNIX
     abstract-sendto:<filename>	groups=FD,SOCKET,RETRY,UNIX
     create:<filename>	groups=FD,REG,NAMED
     exec:<command-line>	groups=FD,FIFO,SOCKET,EXEC,FORK,TERMIOS,PTY,PARENT,UNIX
     fd:<num>	groups=FD,FIFO,CHR,BLK,REG,SOCKET,TERMIOS,UNIX,IP4,IP6,UDP,TCP,SCTP
     gopen:<filename>	groups=FD,FIFO,CHR,BLK,REG,SOCKET,NAMED,OPEN,TERMIOS,UNIX
     interface:<interface>	groups=FD,SOCKET
     ip-datagram:<host>:<protocol>	groups=FD,SOCKET,RANGE,IP4,IP6
     ip-recv:<protocol>	groups=FD,SOCKET,RANGE,IP4,IP6
     ip-recvfrom:<protocol>	groups=FD,SOCKET,CHILD,RANGE,IP4,IP6
     ip-sendto:<host>:<protocol>	groups=FD,SOCKET,IP4,IP6
     ip4-datagram:<host>:<protocol>	groups=FD,SOCKET,RANGE,IP4
     ip4-recv:<protocol>	groups=FD,SOCKET,RANGE,IP4
     ip4-recvfrom:<protocol>	groups=FD,SOCKET,CHILD,RANGE,IP4
     ip4-sendto:<host>:<protocol>	groups=FD,SOCKET,IP4
     ip6-datagram:<host>:<protocol>	groups=FD,SOCKET,RANGE,IP6
     ip6-recv:<protocol>	groups=FD,SOCKET,RANGE,IP6
     ip6-recvfrom:<protocol>	groups=FD,SOCKET,CHILD,RANGE,IP6
     ip6-sendto:<host>:<protocol>	groups=FD,SOCKET,IP6
     open:<filename>	groups=FD,FIFO,CHR,BLK,REG,NAMED,OPEN,TERMIOS
     openssl:<host>:<port>	groups=FD,SOCKET,CHILD,RETRY,IP4,IP6,TCP,OPENSSL
     openssl-listen:<port>	groups=FD,SOCKET,LISTEN,CHILD,RETRY,RANGE,IP4,IP6,TCP,OPENSSL
     pipe:<filename>	groups=FD,FIFO,NAMED,OPEN
     proxy:<proxy-server>:<host>:<port>	groups=FD,SOCKET,CHILD,RETRY,IP4,IP6,TCP,HTTP
     pty	groups=FD,NAMED,TERMIOS,PTY
     readline	groups=FD,READLINE,TERMIOS
     sctp-connect:<host>:<port>	groups=FD,SOCKET,CHILD,RETRY,IP4,IP6,SCTP
     sctp-listen:<port>	groups=FD,SOCKET,LISTEN,CHILD,RETRY,RANGE,IP4,IP6,SCTP
     sctp4-connect:<host>:<port>	groups=FD,SOCKET,CHILD,RETRY,IP4,SCTP
     sctp4-listen:<port>	groups=FD,SOCKET,LISTEN,CHILD,RETRY,RANGE,IP4,SCTP
     sctp6-connect:<host>:<port>	groups=FD,SOCKET,CHILD,RETRY,IP6,SCTP
     sctp6-listen:<port>	groups=FD,SOCKET,LISTEN,CHILD,RETRY,RANGE,IP6,SCTP
     socket-connect:<domain>:<protocol>:<remote-address>	groups=FD,SOCKET,CHILD,RETRY
     socket-datagram:<domain>:<type>:<protocol>:<remote-address>	groups=FD,SOCKET,RANGE
     socket-listen:<domain>:<protocol>:<local-address>	groups=FD,SOCKET,LISTEN,CHILD,RETRY,RANGE
     socket-recv:<domain>:<type>:<protocol>:<local-address>	groups=FD,SOCKET,RANGE
     socket-recvfrom:<domain>:<type>:<protocol>:<local-address>	groups=FD,SOCKET,CHILD,RANGE
     socket-sendto:<domain>:<type>:<protocol>:<remote-address>	groups=FD,SOCKET
     socks4:<socks-server>:<host>:<port>	groups=FD,SOCKET,CHILD,RETRY,IP4,IP6,TCP,SOCKS4
     socks4a:<socks-server>:<host>:<port>	groups=FD,SOCKET,CHILD,RETRY,IP4,IP6,TCP,SOCKS4
     stderr	groups=FD,FIFO,CHR,BLK,REG,SOCKET,TERMIOS,UNIX,IP4,IP6,UDP,TCP,SCTP
     stdin	groups=FD,FIFO,CHR,BLK,REG,SOCKET,TERMIOS,UNIX,IP4,IP6,UDP,TCP,SCTP
     stdio	groups=FD,FIFO,CHR,BLK,REG,SOCKET,TERMIOS,UNIX,IP4,IP6,UDP,TCP,SCTP
     stdout	groups=FD,FIFO,CHR,BLK,REG,SOCKET,TERMIOS,UNIX,IP4,IP6,UDP,TCP,SCTP
     system:<shell-command>	groups=FD,FIFO,SOCKET,EXEC,FORK,TERMIOS,PTY,PARENT,UNIX
     tcp-connect:<host>:<port>	groups=FD,SOCKET,CHILD,RETRY,IP4,IP6,TCP
     tcp-listen:<port>	groups=FD,SOCKET,LISTEN,CHILD,RETRY,RANGE,IP4,IP6,TCP
     tcp4-connect:<host>:<port>	groups=FD,SOCKET,CHILD,RETRY,IP4,TCP
     tcp4-listen:<port>	groups=FD,SOCKET,LISTEN,CHILD,RETRY,RANGE,IP4,TCP
     tcp6-connect:<host>:<port>	groups=FD,SOCKET,CHILD,RETRY,IP6,TCP
     tcp6-listen:<port>	groups=FD,SOCKET,LISTEN,CHILD,RETRY,RANGE,IP6,TCP
     tun:<ip-addr>/<bits>	groups=FD,CHR,NAMED,OPEN,INTERFACE
     udp-connect:<host>:<port>	groups=FD,SOCKET,IP4,IP6,UDP
     udp-datagram:<host>:<port>	groups=FD,SOCKET,RANGE,IP4,IP6,UDP
     udp-listen:<port>	groups=FD,SOCKET,LISTEN,CHILD,RANGE,IP4,IP6,UDP
     udp-recv:<port>	groups=FD,SOCKET,RANGE,IP4,IP6,UDP
     udp-recvfrom:<port>	groups=FD,SOCKET,CHILD,RANGE,IP4,IP6,UDP
     udp-sendto:<host>:<port>	groups=FD,SOCKET,IP4,IP6,UDP
     udp4-connect:<host>:<port>	groups=FD,SOCKET,IP4,UDP
     udp4-datagram:<remote-address>:<port>	groups=FD,SOCKET,RANGE,IP4,UDP
     udp4-listen:<port>	groups=FD,SOCKET,LISTEN,CHILD,RANGE,IP4,UDP
     udp4-recv:<port>	groups=FD,SOCKET,RANGE,IP4,UDP
     udp4-recvfrom:<host>:<port>	groups=FD,SOCKET,CHILD,RANGE,IP4,UDP
     udp4-sendto:<host>:<port>	groups=FD,SOCKET,IP4,UDP
     udp6-connect:<host>:<port>	groups=FD,SOCKET,IP6,UDP
     udp6-datagram:<host>:<port>	groups=FD,SOCKET,RANGE,IP6,UDP
     udp6-listen:<port>	groups=FD,SOCKET,LISTEN,CHILD,RANGE,IP6,UDP
     udp6-recv:<port>	groups=FD,SOCKET,RANGE,IP6,UDP
     udp6-recvfrom:<port>	groups=FD,SOCKET,CHILD,RANGE,IP6,UDP
     udp6-sendto:<host>:<port>	groups=FD,SOCKET,IP6,UDP
     unix-client:<filename>	groups=FD,SOCKET,NAMED,RETRY,UNIX
     unix-connect:<filename>	groups=FD,SOCKET,NAMED,RETRY,UNIX
     unix-listen:<filename>	groups=FD,SOCKET,NAMED,LISTEN,CHILD,RETRY,UNIX
     unix-recv:<filename>	groups=FD,SOCKET,NAMED,RETRY,UNIX
     unix-recvfrom:<filename>	groups=FD,SOCKET,NAMED,CHILD,RETRY,UNIX
     unix-sendto:<filename>	groups=FD,SOCKET,NAMED,RETRY,UNIX



名前:
コメント:

最終更新:2011年06月07日 02:42