ソケットオプションSO_REUSEADDRを利用すると、おんなじサーバプロセスの複数のインスタンス
をこれまたおんなじポート上で起動できます。
ただし、個々のインスタンスは異なるローカルIPアドレスを使用する必要があります。
IPエイリアスの手法を利用して、NICに複数のIPアドレスを割り当てたのち、
同一のポート(9877とします)上でサーバプロセスを起動します。
ここで
既に、eth0にipアドレス192.168.11.6が割り当てられていると仮定します。
IPエイリアスの手順は、
$sudo ifconfig eth0:0 192.168.11.12
$sudo ifconfig eth0:1 192.168.11.13
とすることで、
eth0に対して、
3つのIPアドレス(192.168.11.6/192.168.11.12/192.168.11.13)が割り当てられている状況を作ることが出来ます。
⬇で赤字で示したようにソケットオプションSO_REUSEADDRを有効にし、
SO_REUSEADDRを有効にしたエコーサーバ
#include "unp.h"
int
main(int argc, char **argv)
{
int listenfd, connfd;
pid_t childpid;
socklen_t clilen;
struct sockaddr_in cliaddr, servaddr;
int yes = 1;
if (argc != 2)
err_quit("usage: tcpcli <IPaddress>");
listenfd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
// servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(9877);
Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
Setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));
Listen(listenfd, LISTENQ);
for ( ; ; ) {
clilen = sizeof(cliaddr);
connfd = Accept(listenfd, (SA *) &cliaddr, &clilen);
if ( (childpid = Fork()) == 0) { /* child process */
Close(listenfd); /* close listening socket */
str_echo(connfd); /* process the request */
exit(0);
}
Close(connfd); /* parent closes connected socket */
}
}
上記をコンパイルした後に出来る実行ファイルを仮にtcpservとしたとき、
$./tcpserv 192.168.11.6 &
$./tcpserv 192.168.11.12 &
$./tcpserv 192.168.11.13 &
とすることで、同一ポート(9877)で起動する複数のサーバプロセスを起動出来ます。
その後、上記プロセスが確実に起動していることを確認するために、
ps aux | grep tcp
とすることで起動を確認出来ます。
次にこれらプロセスのソケットがリッスン状態になっていることを検証するために、
netstatコマンドとgrepコマンドを利用して、リッスンしているTCPプロトコルとポートを表示します。
$netstat -an | grep tcp
netstatにanオプションを付与して起動すると、アクティブなプロトコルとリッスンしているポートが表示されます。
その後、|(パイプ)で出力をgrepコマンドに渡し、文字列tcpを検索してます。
出力結果は、⬇のようになり192.168.11.6:9877 / 192.168.11.12:9877 / 192.168.11.13:9877
がリッスン状態であることが分ります。