今回はちょっとした技術メモです。言語検索技術にも改善の余地はあるでもチョロっと述べたんですが、国内には専門的な技術系ノウハウの記事が少ないです。なので、そんなニッチな記事を残しておきます。
タイトルの通り、ソケット単位でキープアライブ間隔を設定する方法についてです。一般人からすれば、なんじゃそりゃ~でしょうね。一週間前の私も一緒そうでした。言葉の説明が要りますね。
まず一般的にソケットとは、「電球あるいは類似形状の照明用電気器具を電気回路に接続するための接点を構成する電気部品のうち、雌型のもの」だそうです。まぁ難しく考えずに、豆電球の下の金属部分のことだと思えばいいです。
ITにおけるソケットもここから派生した言葉でしょう。ちなみに、「プログラム間でデータの送受信を行うための標準的なAPI」です。って言われてもそもそもAPIがわかんないですよね。でもAPIが何かは説明しません。これを説明しようとしてもまたわからないことが増えるからです。
イメージとしては、APIはコンセントみたいなものです。例えば、テレビをつけるためにはテレビと壁にあるコンセントの差込口をコンセントで繋ぐ必要があります。コンセントがないと、電気を送ることができないからです。同様に、APIがないとプログラムからプログラムにデータを送ることができません。
この場合、ソケットとはコンセントのプラグ形状みたいなものです。例えば、コンセント差込口の形と言えばどの家庭でも同じ豚の鼻みたいな形ですが、もう片一方のプラグの形は同じとは限りません。テレビと繋ぐならこの形、携帯と繋ぐならこの形、といった違いがあります。そんな数あるコンセントの形状のうちの一つがソケット程度に考えればよいでしょう。本来のソケットの意味にも近いです。
通信プログラムを作りたい場合は、ソケットをプログラムの中で作成する必要があります。なぜかというと、住宅とは違って初めからコンセントの差込口が用意されているわけではないからです。ソケットを用意して初めて、コンセントを繋げる(通信する)ことができる状態になります。
ソケットの説明が長くなってしまいました。続いてはキープアライブについてです。キープアライブは「通信が生きているかを確認する信号」のことです。通信路が確立されていても、電流とは異なりデータは必要な時にしか送られません。また、コンセントとは違って、繋がっているか繋がっていないかを目視で判断することは不可能です。そのため、相手のプログラムと通信ができているかを確認するために、一定の間隔で信号のやり取りを行う機能がキープアライブです。
キープアライブの間隔は通常、レジストリの設定で好きな値にすることができます。(この方法はネットで調べればすぐに出てくるので割愛します。)しかし、この方法だと残念ながらOSレベルでの設定値になってしまいます。つまりソケット単位で変更することができないんですね。まぁコンセントの差込口ごとに流れる電流の大きさを変えるようなものなので、一筋縄ではいきません。
しかし調べたところ、ソケット単位でキープアライブ間隔を設定する方法が存在しました。ちなみに私のPC環境はWindows 7 Professional、開発環境はVisual Studio C++ 2010です。
まず、C++でソケット通信を行うためにはWinsockというAPIを利用するるのが一般的です。具体的には、ソースファイルの冒頭で<winsock2.h>をインクルードするだけです(標準で開発環境にWinsockは含まれています)。必要に応じて<ws2tcpip.h>もインクルードすると良いでしょう。クライアント側、サーバ側の両方で必要なヘッダファイルです。
Winsockを用いた通信プログラムですが、サーバ側は一般的には以下のような順で関数が呼び出されます。
-------------------------------------------------------
socket()・・・ソケットの生成
⇓
bind()・・・アドレスとソケットの関連付け
⇓
listen()・・・接続スタンバイ
⇓
accept()・・・クライアントから接続要求があると新規ソケットを生成
⇓
send()/ recv()・・・データの送受信
⇓
closesocket()・・・ソケット終了
-------------------------------------------------------
これに対し、クライアント側では、以下のようになります。
-------------------------------------------------------
socket()・・・ソケットの生成
⇓
connect()・・・サーバ側に接続要求
⇓
send()/ recv()・・・データの送受信
⇓
closesocket()・・・ソケット終了
-------------------------------------------------------
ここにキープアライブのオプションを変更するためのコードを追加します。使用するのは、tcp_keepalive構造体とWSAIoctl()関数です。tcp_keepalive構造体を使用するためには、<Mstcpip.h>をインクルードする必要があります。
tcp_keepalive型のオブジェクトを初めに生成しておき、メンバ変数のkeepalivetimeに数値を入力してやれば、それがキープアライブ間隔(ms)となります。そして、connect関数を呼び出す前にWSAIoctl()関数を呼び出して、tcp_keepaliveとソケットの関連付けを行います。
WSAIoctl関数の引数は、9個ありますが、以下のように指定してやれば問題ありません。
WSAIoctl(ソケット名, SIO_KEEPALIVE_VALS, &(tcp_keepalive型の変数), sizeof(tcp_keepalive型の変数), NULL, 0, &(DWORD型の変数), NULL, NULL)
例えば宣言時に、
SOCKET s;
struct tcp_keepalive tka;
DWORD dw = 0;
とした場合は、
WSAIoctl(s, SIO_KEEPALIVE_VALS, &tka, sizeof(tka), NULL, 0, &dw, NULL, NULL);
でオッケーです。なお、キープアライブの設定をソケットに反映させるにはSIO_KEEPALIVE_VALSを第二引数で与えてやる必要があります。ソケットと同じ数だけtcp_keepalive構造体を用意し、ソケットと同じ数だけWSAIoctl()関数を呼び出せば、ソケット毎にキープアライブ間隔を設定することが可能です。ぜひお試しあれ〜。