hana_shinのLinux技術ブログ

Linuxの技術情報を掲載しています。特にネットワークをメインに掲載していきます。

ソケットオプションの使い方(SO_RCVTIMEO編)



1 SO_RCVTIMEOとは?

SO_RCVTIMEOは、受信系システムコール(read, recv, recvfrom, recvmsg)に対して使用するソケットオプションです。これらシステムコールのデフォルト動作はブロッキングモードです。したがって、ソケットの受信バッファに受信データが届くまで、システムコールの実行が完了しません(ブロックしたままになります)。しかし、SO_RCVTIMEOを使うと、データを受信しなくても、指定した時間でシステムコールの実行が完了します。

なお、SO_SNDTIMEOについては、ソケットオプションの使い方(SO_SNDTIMEO編) - hana_shinのLinux技術ブログを参照してください。

2 検証環境

2.1 ネットワーク構成

サーバとクライアントの2台構成です。図中のenp1s0はNICの名前です。

                               192.168.122.0/24
client(enp1s0) ------------------------------------------(enp1s0) server
            .177                                       .68

2.2 版数

サーバとクライアントのAlmaLinuxの版数は以下のとおりです。

[root@server ~]# cat /etc/redhat-release
AlmaLinux release 8.6 (Sky Tiger)

カーネル版数は以下のとおりです。

[root@server ~]# uname -r
4.18.0-372.9.1.el8.x86_64

クライアントからサーバの11111番ポートにアクセスできるようにするため、TCPの11111番ポートを解放します。なお、firewall-cmdの使い方は、firewall-cmdの使い方は、firewall-cmdの使い方 - hana_shinのLinux技術ブログを参照してください。

[root@server ~]# firewall-cmd --add-port=11111/tcp
success

ルールを確認します。11111番ポートへのアクセスを許可するルールが追加されたことがわかります。

[root@server ~]# firewall-cmd --list-ports
11111/tcp

3 テストプログラム(以降TP)の作成

サーバ、クライアントで実行するTPを作成します。ソースコードを見やすくするため、意図的に異常処理は省略しています。また、ソケットオプションの動作確認を目的としているため、実用的なプログラムにはなっていません。

・サーバ側:ncコマンドを使います。なお、ncコマンドのインストール方法、使い方は、ncコマンドの使い方(ネットワーク実験の幅が広がるなぁ~) - hana_shinのLinux技術ブログを参照してください。
・クライアント側:以下のTPをコンパイルして使用します。なお、コードを見やすくするため、異常処理は意図的に省略しています。

[root@client ~]# cat cl.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>

int main(int argc, char *argv[])
{
  int sock;
  struct sockaddr_in server;
  struct timeval timeout;
  char buf[4096];

  sock = socket(AF_INET, SOCK_STREAM, 0);
  server.sin_family = AF_INET;
  server.sin_port = htons(11111);
  server.sin_addr.s_addr = inet_addr("192.168.122.68");

  if(atoi(argv[1]) != 0) {
    timeout.tv_sec =atoi(argv[1]);
    timeout.tv_usec = 0;
    setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof timeout);
  }

  connect(sock, (struct sockaddr *)&server, sizeof(server));
  read(sock, buf, sizeof(buf));
  perror("read");
  close(sock);
  return 0;
}

TPの第1引数の意味は次のとおりです。

第1引数 意味
0 ソケットの受信バッファにデータが到着するまで、システムコールの実行は完了しません(ブロックしたままになります)
0以外 システムコールの実行時間を指定します。ソケットの受信バッファにデータが到着しなくても、指定した時間でシステムコールの実行が完了します

TPをコンパイルします。

[root@client ~]# gcc -Wall -o cl cl.c

4 動作確認

サー側でncコマンドを実行します。

[root@server ~]# nc -kl 11111

4.1 TPの引数に1を指定した場合

readシステムコールの実行時間を確認するため、straceコマンドを使用します。straceの実行結果(3行目の右端)を確認すると、readシステムコールの実行時間が1.01秒であることがわかります。TPの引数に指定した1秒におおよそ一致していることがわかります。なお、straceコマンドの使い方は、https://hana-shin.hatenablog.com/entry/2021/12/25/215551:titileを参照してください。

[root@client ~]# strace -ttT -e trace=read ./cl 1
20:25:27.760788 read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\260\255\3\0\0\0\0\0"..., 832) = 832 <0.000267>
20:25:27.765834 read(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32) = 32 <0.000912>
20:25:27.784649 read(3, 0x7ffcee8e6620, 4096) = -1 EAGAIN (リソースが一時的に利用できません) <1.010118>
read: Resource temporarily unavailable
20:25:28.805899 +++ exited with 0 +++

4.2 TPの引数に2を指定した場合

次に、TPの引数に2秒を指定してみます。straceの実行結果(3行目の右端)を確認すると、readシステムコールの実行時間が2.02秒であることがわかります。TPの引数に指定した2秒におおよそ一致していることがわかります。

[root@client ~]# strace -ttT -e trace=read ./cl 2
20:31:55.437992 read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\260\255\3\0\0\0\0\0"..., 832) = 832 <0.000313>
20:31:55.440177 read(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32) = 32 <0.000200>
20:31:55.447935 read(3, 0x7ffeda0dc200, 4096) = -1 EAGAIN (リソースが一時的に利用できません) <2.018727>
read: Resource temporarily unavailable
20:31:57.481223 +++ exited with 0 +++

4.3 TPの引数に0を指定した場合

最後に、TPの引数に0秒を指定してみます。引数に0を指定すると、システムコールの実行が完了しないことがわかります。

[root@client ~]# strace -ttT -e trace=read ./cl 0
20:32:24.817061 read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\260\255\3\0\0\0\0\0"..., 832) = 832 <0.000425>
20:32:24.823672 read(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32) = 32 <0.000666>
20:32:24.840294 read(3,

Z 参考情報

私が業務や記事執筆で参考にした書籍を以下のページに記載します。
Linux技術のスキルアップをしよう! - hana_shinのLinux技術ブログ