2015年4月21日火曜日

伊豆市リトルシニア 静岡蒲原シニアと練習試合やりました

久しぶりの野球ネタ


既に入団して早1年が過ぎ去りました...時間が経つのも早いものです。
入団以来、野球ネタは書いてなかったのですが、これからちょっとづつ書こうかとは思います。

今日は天城グラウンドで静岡蒲原シニアさんとの練習試合でした、若干曇りぎみ、雨もちょっとパラつきましたが、試合に支障ない程度で良かってです。

 

なんと!、女子が入団しました


まじかっ! 女子の入団だってぇー!

本日はたまたまだったのですが、新1年生で女子が入団するということで、みんなとはちょっと遅れた入団式だったのですが立ち会うことができました。


練習だって結構ハードなのに、この中で野球をやっていこうって凄い決断ですね、頭が下がります、たいしたもんです。

入団おめでとうございます、3年間頑張ってください。

男どもも負けてられないですね...

試合のほう


本日3試合、私は審判として出場しました(体力がないので交代制ですが)、野球のことはあまり詳しく知らないので試合の気の利いた説明とかはできませんが、1年前に比べたらみんなプレーが格好良く見えました。


とりあえず、お疲れさまでした、こう皆で並ぶとなかなか逞しくなったなぁーと少し感じる近頃です。


本日も審判業務が終了しました、で、最後はこれで締めましょう...


皆さん、朝早くから1日ご苦労さまでした、また頑張ります...

2015年4月18日土曜日

MySQL-5.6.24へQ4Mを入れ込んだgentooのebuildをつくりました

Q4Mを再び...


Socket遊びが終わらない和人くんはほっといて、Q4Mの新しいバージョンをgentooで使えるようにebuildを作成しました。 前回はMySQLの5.1用のプラグインとして作りましたが、もう古いということで新しめのMySQLとQ4Mで作り直しました。



インストール


既にMySQLをインストールされている方は気をつけてください まずこうして
karky7 ~ # layman -a karky7
バージョン指定でこうする
karky7 ~ # emerge -u "=dev-db/mysql-5.6.24::karky7"
サービスを開始
karky7 ~ # systemctl start mysqld
Q4Mのプラグインをインストール
karky7 ~ # mysql -u root < /usr/share/mysql/support-files/install.sql
確認
karky7 ~ # mysql -u root
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 4
Server version: 5.6.24-log Source distribution

Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show plugins;
+----------------------------+--------+--------------------+--------------------+---------+
| Name                       | Status | Type               | Library            | License |
+----------------------------+--------+--------------------+--------------------+---------+
| binlog                     | ACTIVE | STORAGE ENGINE     | NULL               | GPL     |
| mysql_native_password      | ACTIVE | AUTHENTICATION     | NULL               | GPL     |
| mysql_old_password         | ACTIVE | AUTHENTICATION     | NULL               | GPL     |
| sha256_password            | ACTIVE | AUTHENTICATION     | NULL               | GPL     |
| MEMORY                     | ACTIVE | STORAGE ENGINE     | NULL               | GPL     |
| MRG_MYISAM                 | ACTIVE | STORAGE ENGINE     | NULL               | GPL     |
| CSV                        | ACTIVE | STORAGE ENGINE     | NULL               | GPL     |
| MyISAM                     | ACTIVE | STORAGE ENGINE     | NULL               | GPL     |
| PERFORMANCE_SCHEMA         | ACTIVE | STORAGE ENGINE     | NULL               | GPL     |
| BLACKHOLE                  | ACTIVE | STORAGE ENGINE     | NULL               | GPL     |
| InnoDB                     | ACTIVE | STORAGE ENGINE     | NULL               | GPL     |
| INNODB_TRX                 | ACTIVE | INFORMATION SCHEMA | NULL               | GPL     |
| INNODB_LOCKS               | ACTIVE | INFORMATION SCHEMA | NULL               | GPL     |
| INNODB_LOCK_WAITS          | ACTIVE | INFORMATION SCHEMA | NULL               | GPL     |
| INNODB_CMP                 | ACTIVE | INFORMATION SCHEMA | NULL               | GPL     |
| INNODB_CMP_RESET           | ACTIVE | INFORMATION SCHEMA | NULL               | GPL     |
| INNODB_CMPMEM              | ACTIVE | INFORMATION SCHEMA | NULL               | GPL     |
| INNODB_CMPMEM_RESET        | ACTIVE | INFORMATION SCHEMA | NULL               | GPL     |
| INNODB_CMP_PER_INDEX       | ACTIVE | INFORMATION SCHEMA | NULL               | GPL     |
| INNODB_CMP_PER_INDEX_RESET | ACTIVE | INFORMATION SCHEMA | NULL               | GPL     |
| INNODB_BUFFER_PAGE         | ACTIVE | INFORMATION SCHEMA | NULL               | GPL     |
| INNODB_BUFFER_PAGE_LRU     | ACTIVE | INFORMATION SCHEMA | NULL               | GPL     |
| INNODB_BUFFER_POOL_STATS   | ACTIVE | INFORMATION SCHEMA | NULL               | GPL     |
| INNODB_METRICS             | ACTIVE | INFORMATION SCHEMA | NULL               | GPL     |
| INNODB_FT_DEFAULT_STOPWORD | ACTIVE | INFORMATION SCHEMA | NULL               | GPL     |
| INNODB_FT_DELETED          | ACTIVE | INFORMATION SCHEMA | NULL               | GPL     |
| INNODB_FT_BEING_DELETED    | ACTIVE | INFORMATION SCHEMA | NULL               | GPL     |
| INNODB_FT_CONFIG           | ACTIVE | INFORMATION SCHEMA | NULL               | GPL     |
| INNODB_FT_INDEX_CACHE      | ACTIVE | INFORMATION SCHEMA | NULL               | GPL     |
| INNODB_FT_INDEX_TABLE      | ACTIVE | INFORMATION SCHEMA | NULL               | GPL     |
| INNODB_SYS_TABLES          | ACTIVE | INFORMATION SCHEMA | NULL               | GPL     |
| INNODB_SYS_TABLESTATS      | ACTIVE | INFORMATION SCHEMA | NULL               | GPL     |
| INNODB_SYS_INDEXES         | ACTIVE | INFORMATION SCHEMA | NULL               | GPL     |
| INNODB_SYS_COLUMNS         | ACTIVE | INFORMATION SCHEMA | NULL               | GPL     |
| INNODB_SYS_FIELDS          | ACTIVE | INFORMATION SCHEMA | NULL               | GPL     |
| INNODB_SYS_FOREIGN         | ACTIVE | INFORMATION SCHEMA | NULL               | GPL     |
| INNODB_SYS_FOREIGN_COLS    | ACTIVE | INFORMATION SCHEMA | NULL               | GPL     |
| INNODB_SYS_TABLESPACES     | ACTIVE | INFORMATION SCHEMA | NULL               | GPL     |
| INNODB_SYS_DATAFILES       | ACTIVE | INFORMATION SCHEMA | NULL               | GPL     |
| ARCHIVE                    | ACTIVE | STORAGE ENGINE     | NULL               | GPL     |
| partition                  | ACTIVE | STORAGE ENGINE     | NULL               | GPL     |
| QUEUE                      | ACTIVE | STORAGE ENGINE     | libqueue_engine.so | GPL     |
+----------------------------+--------+--------------------+--------------------+---------+
42 rows in set (0.00 sec)
でQUEUEが入ります
 

Q4Mの罠


Q4Mのソースを追加してビルドをすると、ディフォルトのebuildでは以下のエラーでビルドできませんした。
...
...
...
/home/cuomo/workspace/mysql/mysql-5.6.23/storage/q4m/src/boost/static_assert.hpp:119:10: 備考: in expansion of macro ‘BOOST_JOIN’
          BOOST_JOIN(boost_static_assert_typedef_, __LINE__)
          ^
/home/cuomo/workspace/mysql/mysql-5.6.23/storage/q4m/src/boost/optional/optional.hpp:333:8: 備考: in expansion of macro ‘BOOST_STATIC_ASSERT’
        BOOST_STATIC_ASSERT ( ::boost::mpl::not_<is_reference_predicate>::value ) ;
        ^
In file included from /usr/include/features.h:366:0,
                 from /usr/include/assert.h:35,
                 from /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.3/include/g++-v4/cassert:43,
                 from /home/cuomo/workspace/mysql/mysql-5.6.23/storage/q4m/src/queue_cond.cc:1:
/usr/include/bits/mathcalls.h: 大域スコープ:
/usr/include/bits/mathcalls.h:153:1: エラー: declaration of C function ‘long double pow(long double, long double)’ conflicts with
 __MATHCALL (pow,, (_Mdouble_ __x, _Mdouble_ __y));
 ^
/usr/include/bits/mathcalls.h:153:1: エラー: previous declaration ‘double pow(double, double)’ here
 __MATHCALL (pow,, (_Mdouble_ __x, _Mdouble_ __y));
 ^
In file included from /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.3/include/g++-v4/complex:44:0,
                 from /home/cuomo/workspace/mysql/mysql-5.6.23/storage/q4m/src/boost/type_traits/is_complex.hpp:12,
                 from /home/cuomo/workspace/mysql/mysql-5.6.23/storage/q4m/src/boost/type_traits.hpp:81,
                 from /home/cuomo/workspace/mysql/mysql-5.6.23/storage/q4m/src/boost/spirit/home/classic/core/parser.hpp:12,
                 from /home/cuomo/workspace/mysql/mysql-5.6.23/storage/q4m/src/boost/spirit/home/classic/core.hpp:29,
                 from /home/cuomo/workspace/mysql/mysql-5.6.23/storage/q4m/src/boost/spirit/include/classic_core.hpp:11,
                 from /home/cuomo/workspace/mysql/mysql-5.6.23/storage/q4m/src/boost/spirit/core.hpp:25,
                 from /home/cuomo/workspace/mysql/mysql-5.6.23/storage/q4m/src/queue_cond.cc:4:
/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.3/include/g++-v4/cmath: 関数 ‘long double std::pow(long double, long double)’ 内:
/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.3/include/g++-v4/cmath:411:39: エラー: ‘long double std::pow(long double, long double)’ conflicts with previous using declaration ‘long double pow(long double, long double)’
   pow(long double __x, long double __y)
                                       ^
In file included from /home/cuomo/workspace/mysql/mysql-5.6.23/storage/q4m/src/queue_cond.cc:13:0:
/home/cuomo/workspace/mysql/mysql-5.6.23/storage/q4m/src/queue_cond.h: メンバ関数 ‘queue_cond_t::value_t queue_cond_t::pow_func::bop(const queue_cond_t::value_t&, const queue_cond_t::value_t&) const’ 内:
/home/cuomo/workspace/mysql/mysql-5.6.23/storage/q4m/src/queue_cond.h:274:69: エラー: オーバーロードされている ‘pow(const long long int&, const long long int&)’ の呼び出しが曖昧です
       return value_t::int_value(static_cast<long long>(powl(x.l, y.l)));
                                                                     ^
/home/cuomo/workspace/mysql/mysql-5.6.23/storage/q4m/src/queue_cond.h:274:69: 備考: 候補:
In file included from /usr/include/features.h:366:0,
                 from /usr/include/assert.h:35,
                 from /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.3/include/g++-v4/cassert:43,
                 from /home/cuomo/workspace/mysql/mysql-5.6.23/storage/q4m/src/queue_cond.cc:1:
/usr/include/bits/mathcalls.h:153:1: 備考: double pow(double, double)
 __MATHCALL (pow,, (_Mdouble_ __x, _Mdouble_ __y));
 ^
<コマンドライン>:0:6: 備考: long double pow(long double, long double)
In file included from /home/cuomo/workspace/mysql/mysql-5.6.23/storage/q4m/src/queue_cond.cc:13:0:
/home/cuomo/workspace/mysql/mysql-5.6.23/storage/q4m/src/queue_cond.h:275:5: 警告: 制御が非 void 関数の終りに到達しました [-Wreturn-type]
     }
     ^
storage/q4m/CMakeFiles/queue.dir/build.make:57: ターゲット 'storage/q4m/CMakeFiles/queue.dir/src/queue_cond.cc.o' のレシピで失敗しました
make[2]: *** [storage/q4m/CMakeFiles/queue.dir/src/queue_cond.cc.o] エラー 1
CMakeFiles/Makefile2:596: ターゲット 'storage/q4m/CMakeFiles/queue.dir/all' のレシピで失敗しました
make[1]: *** [storage/q4m/CMakeFiles/queue.dir/all] エラー 2
Makefile:136: ターゲット 'all' のレシピで失敗しました
make: *** [all] エラー 2
...
...
pow()関数がconflictしてると起こられます、色々調べてみましたがどうやら、cmakeのオプションの -DWITH_ZLIB=system がQ4Mだとダメらしく、これを -DWITH_ZLIB=bundled にする必要があるようです、このオプションはCOMPRESS()関数などで使うらしいのですが、これをMySQL提供のzlibにするか、システムにインストールされているzlibを利用するかの選択のオプションで、ディフォルトだとsystemになっています。

gentooのディフォルトのebuildが-DWITH_ZLIB=systemでハードコードされていたので、これを修正しました。 多分、どちらのzlibでも動くと思うのですが、たぶんヘッダーのincludeに問題があるような気がします、RedHatでも同じエラーが出てるような気がしました。 時間があれば、ソースコードを追っかけてみます、っていってそのままが多いのですが...

最後にcmakeのオプションサンプル


cmakeのオプションはこんな感じ、参考程度に、MySQL-5.6.23ですが....
cmake --no-warn-unused-cli \
-DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_C_FLAGS_RELWITHDEBINFO=-DNDEBUG \
-DCMAKE_CXX_FLAGS_RELWITHDEBINFO=-DNDEBUG \
-DCMAKE_INSTALL_PREFIX=/usr \
-DMYSQL_DATADIR=/var/lib/mysql \
-DSYSCONFDIR=/etc/mysql \
-DINSTALL_BINDIR=bin \
-DINSTALL_DOCDIR=share/doc/mysql-5.6.23 \
-DINSTALL_DOCREADMEDIR=share/doc/mysql-5.6.23 \
-DINSTALL_INCLUDEDIR=include/mysql \
-DINSTALL_INFODIR=share/info \
-DINSTALL_LIBDIR=lib64 \
-DINSTALL_ELIBDIR=lib64/mysql \
-DINSTALL_MANDIR=share/man \
-DINSTALL_MYSQLDATADIR=/var/lib/mysql \
-DINSTALL_MYSQLSHAREDIR=share/mysql \
-DINSTALL_MYSQLTESTDIR=share/mysql/mysql-test \
-DINSTALL_PLUGINDIR=lib64/mysql/plugin \
-DINSTALL_SBINDIR=sbin \
-DINSTALL_SCRIPTDIR=share/mysql/scripts \
-DINSTALL_SQLBENCHDIR=share/mysql \
-DINSTALL_SUPPORTFILESDIR=/usr/share/mysql \
-DWITH_UNIT_TESTS=OFF \
-DWITH_LIBEDIT=0 \
-DWITH_ZLIB=system \
-DWITHOUT_LIBWRAP=1 \
-DENABLED_LOCAL_INFILE=1 \
-DMYSQL_UNIX_ADDR=/var/run/mysqld/mysqld.sock \
-DINSTALL_UNIX_ADDRDIR=/var/run/mysqld/mysqld.sock \
-DWITH_SSL=system \
-DWITH_DEFAULT_COMPILER_OPTIONS=0 \
-DWITH_DEFAULT_FEATURE_SET=0 \
-DENABLE_DTRACE=OFF \
-DWITH_EDITLINE=bundled \
-DDEFAULT_CHARSET=utf8 \
-DDEFAULT_COLLATION=utf8_general_ci \
-DEXTRA_CHARSETS=all \
-DMYSQL_USER=mysql \
-DMYSQL_UNIX_ADDR=/var/run/mysqld/mysqld.sock \
-DDISABLE_SHARED=OFF \
-DWITH_debug=OFF \
-DWITH_DEBUG=OFF \
-DWITH_Debug=OFF \
-DWITH_EMBEDDED_SERVER=OFF \
-DWITH_profiling=OFF \
-DWITH_PROFILING=OFF \
-DWITH_Profiling=OFF \
-DENABLE_DTRACE=OFF \
-DWITH_ARCHIVE_STORAGE_ENGINE=1 \
-DWITH_BLACKHOLE_STORAGE_ENGINE=1 \
-DWITH_CSV_STORAGE_ENGINE=1 \
-DWITH_HEAP_STORAGE_ENGINE=1 \
-DWITH_INNOBASE_STORAGE_ENGINE=1 \
-DWITH_MYISAMMRG_STORAGE_ENGINE=1 \
-DWITH_MYISAM_STORAGE_ENGINE=1 \
-DWITH_PARTITION_STORAGE_ENGINE=1 \
-DWITH_FEDERATED_STORAGE_ENGINE=OFF \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_INSTALL_DO_STRIP=OFF



2015年4月12日日曜日

和人くんのSO_REUSEADDRオプション癖が抜けない件

和人くん、マジで知ってる!? socketのSO_REUSEADDRオプション


最近マジ、和人のソケット使いが荒すぎて困ってます、そんな時は

「まだ使われていますので、後ほどご利用ください...」

と丁寧にお断りしてください。


 ※画像はイメージです

それでは本題です


サーバー系のコードを見たりしてると、socketを作成しbind()する前にsetsockopt()でSO_REUSEADDRするのがほとんどですが、素直に...

「何でだよ、何でだよ、」

って2回ぐらいおもってしまいましたので、調べました、というか、ほとんど忘れてました。

後から気づきましたが、このソケットオプションを試すのに、こんなやりすぎたコードは必要なかったのですが、書いてしまったので載せます、コードが汚いので何をやっているのか先に図をご確認ください


動作の流れは、

  • 「和人かどうかわからないプロセス」「たぶん和人だと思われるプロセス」をforkします(これがサーバープロセスです)
  • 「たぶん和人だと思われるプロセス」はポート9000でLISTENします
  • 「和人かどうかわからないプロセス」はその後さらに「和人の子」をforkします(これがクライアントプロセスです)
  • 「和人の子」は最大5個まで創られます(どうやって創られたかは不明です)
  • 「和人の子」がいなくなると「和人かどうかわからないプロセス」はSIGCHLDシグナルを受けとりますので、しっかりwaipid()で受け止めて葬り去ります 
process数が腐らないようにsleep()で逃げたり、シグナルハンドラの中でこの関数呼んじゃダメでしょ、とか突っ込まないようにお願いします。


ビルド方法


Linux
$ gcc -g -O0 so_reuseaddr.c -o no_reuse ・・・ SO_REUSEADDRなし
$ gcc -g -O0 so_reuseaddr.c -o no_reuse -DKAZUTO・・・SO_REUSEADDRあり

Solaris
cc -g -O0 so_reuseaddr.c -lsocket -lnsl -o no_reuse
cc -g -O0 so_reuseaddr.c -lsocket -lnsl -DKAZUTO -o reuse
とやりますとそれぞれの実行可能形式のファイルが出来上がります。

試してみる


* SO_REUSEADDRオプションを有効にしない場合
cuomo@karky7 ~ $ ./no_reuse 
和人は創りました(1号) pid=4243
和人の子 pid=4243 は暇人なので 9秒だけ寝るw..
和人は創りました(2号) pid=4245
和人の子 pid=4245 は暇人なので 9秒だけ寝るw..
和人は創りました(3号) pid=4246
和人の子 pid=4246 は暇人なので 6秒だけ寝るw..
和人は創りました(4号) pid=4264
和人の子 pid=4264 は暇人なので 7秒だけ寝るw..
和人は創りました(5号) pid=4265
和人の子 pid=4265 は暇人なので 3秒だけ寝るw..
和人が親なんて信じられるかっ!! もう出るわ!
接続してきた和人の子 ... 192.168.254.21, 和人ポート 58599 <-- accept()が起きた
和人の子供がオワタ(5号) 4246
和人は創りました(5号) pid=4266
和人の子 pid=4266 は暇人なので 3秒だけ寝るw..
和人が親なんて信じられるかっ!! もう出るわ!
接続してきた和人の子 ... 192.168.254.21, 和人ポート 58600
...
...
和人が親なんて信じられるかっ!! もう出るわ!
和人の子供がオワタ(5号) 4266
和人は創りました(5号) pid=4273
接続してきた和人の子 ... 192.168.254.21, 和人ポート 58605
和人が親なんて信じられるかっ!! もう出るわ!
和人の子供がオワタ(5号) 4269
和人は創りました(5号) pid=4274
割り込み
...
...
cuomo@karky7 ~ $ ./no_reuse <----- 2回目の実行
和人は創りました(1号) pid=4277
ああぁー、やっちまった...: Address already in use <---- まだ使えない
和人の子供がオワタ(1号) 4276
和人は創りました(1号) pid=4278
和人の子 pid=4278 は暇人なので 3秒だけ寝るw..
和人の子 pid=4277 は暇人なので 3秒だけ寝るw..
和人は創りました(2号) pid=4280
和人の子 pid=4280 は暇人なので 3秒だけ寝るw..
割り込み
...
...
cuomo@karky7 ~ $ netstat -tpn
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 192.168.254.21:58603      192.168.254.21:9000       TIME_WAIT   -                   
tcp        0      0 192.168.254.21:9000       192.168.254.21:58605      TIME_WAIT   -                   
tcp        0      0 192.168.254.21:58602      192.168.254.21:9000       TIME_WAIT   -                   
tcp        0      0 192.168.254.21:9000       192.168.254.21:58604      TIME_WAIT   -                   
tcp        0      0 192.168.254.21:58599      192.168.254.21:9000       TIME_WAIT   -                   
tcp        0      0 192.168.254.21:58600      192.168.254.21:9000       TIME_WAIT   -                   
tcp        0      0 192.168.254.21:58601      192.168.254.21:9000       TIME_WAIT   -                   
cuomo@karky7 ~ $

SO_REUSEADDRオプションをつけないと2回め以降のbind()が「Address already in use」で失敗し、サーバープロセスが起動できません。よって和人の子は孤児のまま彷徨う事になります。

ようするに

 「192.168.254.21:9000へbind()したいのですが、まだそのコネクションがTIME_WAIT状態で残っているのでダメですよ」

ってこと、じゃSO_REUSEADDRをつけるとどうなるのと言えば...

* SO_REUSEADDRを有効にした場合

「和人! Socketをリユーズするんだ!」でソケットにオプションを追加しています
~ $ ./reuse
和人は創りました(1号) pid=5966
和人! Socketをリユーズするんだ! <----- SO_REUSEADDRをいれる
和人の子 pid=5966 は暇人なので 6秒だけ寝るw..
和人は創りました(2号) pid=5967
和人の子 pid=5967 は暇人なので 3秒だけ寝るw..
和人は創りました(3号) pid=5969
和人の子 pid=5969 は暇人なので 7秒だけ寝るw..
和人が親なんて信じられるかっ!! もう出るわ!
接続してきた和人の子 ... 192.168.254.21, 和人ポート 58689
和人の子供がオワタ(3号) 5967
和人は創りました(3号) pid=5970
...
...
和人の子供がオワタ(4号) 5969
和人は創りました(4号) pid=5977
和人の子 pid=5977 は暇人なので 8秒だけ寝るw..
和人は創りました(5号) pid=5994
和人の子 pid=5994 は暇人なので 8秒だけ寝るw..
和人が親なんて信じられるかっ!! もう出るわ!
接続してきた和人の子 ... 192.168.254.21, 和人ポート 58694
和人の子供がオワタ(5号) 5973
和人は創りました(5号) pid=5996
和人の子 pid=5996 は暇人なので 4秒だけ寝るw..
割り込み
~ $ ./reuse
和人は創りました(1号) pid=5999
和人! Socketをリユーズするんだ!
和人の子 pid=5999 は暇人なので 5秒だけ寝るw..
和人は創りました(2号) pid=6001
和人の子 pid=6001 は暇人なので 8秒だけ寝るw..
和人は創りました(3号) pid=6002
和人の子 pid=6002 は暇人なので 8秒だけ寝るw..
和人が親なんて信じられるかっ!! もう出るわ!
接続してきた和人の子 ... 192.168.254.21, 和人ポート 58695
和人の子供がオワタ(3号) 5999
和人は創りました(3号) pid=6003
...
...
和人の子 pid=6028 は暇人なので 3秒だけ寝るw..
和人が親なんて信じられるかっ!! もう出るわ!
接続してきた和人の子 ... 192.168.254.21, 和人ポート 58702
和人の子供がオワタ(4号) 6026
和人は創りました(4号) pid=6029
和人の子 pid=6029 は暇人なので 3秒だけ寝るw..
~ $ ./reuse
和人! Socketをリユーズするんだ!
和人は創りました(1号) pid=6033
和人の子 pid=6033 は暇人なので 9秒だけ寝るw..
和人は創りました(2号) pid=6034
和人の子 pid=6034 は暇人なので 7秒だけ寝るw..
和人は創りました(3号) pid=6036
和人は創りました(4号) pid=6037
...
...

~ $ netstat -tpn
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 192.168.254.21:58698      192.168.254.21:9000       TIME_WAIT   -                   
tcp        0      0 192.168.254.21:58700      192.168.254.21:9000       TIME_WAIT   -                   
tcp        0      0 192.168.254.21:58704      192.168.254.21:9000       TIME_WAIT   -                   
tcp        0      0 192.168.254.21:58699      192.168.254.21:9000       TIME_WAIT   -                   
tcp        0      0 192.168.254.21:58703      192.168.254.21:9000       TIME_WAIT   -                   
tcp        0      0 192.168.254.21:9000       192.168.254.21:58702      TIME_WAIT   -                   
tcp        0      0 192.168.254.21:58701      192.168.254.21:9000       TIME_WAIT   -                   
tcp        0      0 192.168.254.21:58702      192.168.254.21:9000       TIME_WAIT   -    
TIME_WAITが残ってても、必ずbind()が成功する。

サーバーを再起動とかかけたときにSO_REUSEADDRをしてないと、コネクションが綺麗に始末されるまでサーバーを起動できないって事になりかねませんね、これは

危ない!

ということで、サーバーを書くときはこのオプションをつけましょうというお話、

まぁ和人はどうでもいいが...

もう、和人のSocketネタはつまらないからやめる...

最後にコード


#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <time.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

/* Solaris: cc -g -O0 so_reuseaddr.c -lsocket -lnsl -o no_reuse */
/*          cc -g -O0 so_reuseaddr.c -lsocket -lnsl -DKAZUTO -o reuse */

/* Linux:   gcc -g -O0 so_reuseaddr.c -o no_reuse */
/*          gcc -g -O0 so_reuseaddr.c -DKAZUTO -o reuse */
int process = 0;

void sig_child(int);
void child_func(void);
void server_func(void);
void set_sockaddrin(struct sockaddr_in *, int);

int main(void)
{
  pid_t pid;

  struct sigaction sa, osa;
  sigemptyset(&sa.sa_mask);
  sa.sa_flags = 0;
  sa.sa_handler = &sig_child;
  sa.sa_flags |= SA_RESTART;
  sigaction(SIGCHLD, &sa, &osa);

  pid = fork();
  if(pid == 0) {
    server_func();
  } else if(pid < 0) {
    perror("しょっぱなから無理でしょ");
    return -1;
  }

  while(1) {
    if(process < 5) {
      pid = fork();
      if(pid == 0) {
        child_func();
      } else if(pid < 0) {
        perror("和人は小作りに失敗しました");
      } else {
        process++;
        printf("和人は創りました(%d号) pid=%d\n", process, pid);
      }
    }
    sleep(2);
  }
  return 1;
}

void server_func(void)
{
  int sock, result, con;
  socklen_t len;
  struct sockaddr_in serv, cli;
  char buff[1024];
  const char *p;
#ifdef KAZUTO
  /* SO_REUSEADDRを有効にする場合は1、無効にする場合は0をセット */
  int reuseaddr = 1;
#endif

  sock = socket(AF_INET, SOCK_STREAM, 0);
  if(sock == -1) {
    perror("ソケット...どうしてくれんだ");
    exit(EXIT_FAILURE);
  }
  set_sockaddrin(&serv, sizeof(serv));

#ifdef KAZUTO
  puts("和人! Socketをリユーズするんだ!");
  result = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
        (const void *) &reuseaddr, sizeof(int));
  if(result == -1) {
    perror("和人はできまい、、がセットできないよぉー\n");
    exit(EXIT_FAILURE);
  }
#endif

  if (bind(sock, (struct sockaddr*)&serv, sizeof(serv)) == -1) {
    perror("ああぁー、やっちまった...");
    exit(EXIT_FAILURE);
  }

  if(listen(sock, 15) < 0) {
    perror("ああぁー、リッスンゴレライ...");
    exit(EXIT_FAILURE);
  }
  
  while(1) {
    len = sizeof(cli);
    con = accept(sock, (struct sockaddr*)&cli, &len);
    if(con < 0) {
      perror("なにが起こった和人くん!");
    } else {
      p = inet_ntop(AF_INET, &cli.sin_addr, buff, sizeof(buff));
      printf("接続してきた和人の子 ... %s, 和人ポート %d\n",
             p,
             ntohs(cli.sin_port));
      close(con);
    }
  }
}

void child_func(void)
{
  int sock;
  int r, result;
  time_t t;
  pid_t pid;
  struct sockaddr_in serv;
  
  pid = getpid();

  sock = socket(AF_INET, SOCK_STREAM, 0);
  if(sock == -1) {
    perror("ソケット...そそそ");
    exit(EXIT_FAILURE);
  }
  set_sockaddrin(&serv, sizeof(serv));

  r = 0;
  while(r < 3) {
    t = time(NULL); 
    srand(t);
    r = rand() % 10;
  }

  printf("和人の子 pid=%d は暇人なので %d秒だけ寝るw..\n", pid, r);
  sleep(r);

  if(connect(sock, (struct sockaddr*)&serv, sizeof(serv)) < 0) {
    perror("和人め裏切ったか...");
    exit(1);
  }

  puts("和人が親なんて信じられるかっ!! もう出るわ!");
  close(sock);
  exit(1);
}

void sig_child(int no)
{
  pid_t pid;
  int stat;
  while((pid = waitpid(-1, &stat, WNOHANG)) > 0) {
    printf("和人の子供がオワタ(%d号) %d\n", process, pid);
    if(process > 0) {
      process--;
    }
  }
  return;
}

void set_sockaddrin(struct sockaddr_in *serv, int size)
{
  bzero(serv, size);
  serv->sin_family = AF_INET;
  inet_pton(AF_INET, "192.168.254.21", &serv->sin_addr.s_addr);
  serv->sin_port = htons(9000);
}


Socket遊びは止めるんだ... 和人...