Armadilloフォーラム

Keep-Aliveの挙動について

y_kudo_ncpl

2016年12月19日 11時52分

工藤@NCPLと申します。

Armadillo440 のUSBポートに弊社装置に接続して、Ethernet⇔USBの変換機のような使い方をしています。

TCPのKeep-Aliveの挙動について教えてください。
切断検出のため,KeepAliveを使っております。

目論見としては10秒後から1秒間隔でKeepAlive、10回で応答が無ければ切断なのですが
実際に動作させたところ、
・10秒後から10秒間隔で送信。
・3回の送信後、WireSharkで観察すると応答が返っているように見えているにも関わらずArmadillo側から切断
(WireSharkのスクリーンショットを添付します。192.168.0.3がArmadillo,192.168.0.20がPCです。)
という、思惑と異なる挙動が出て、原因を探しております。

以下はソースコード当該箇所の抜粋です。
設定の間違い、あるいは設定の漏れがあるのでしょうか?

define    KEEPALIVE_DELAY    10
#define    KEEPALIVE_INTERVAL 1
#define    KEEPALIVE_ERRCOUNT 10
 
 
    /*Ignore SIGPIPE これをやらないと相手にクローズされた後読み書きするとプロセス落ちる*/
    /*またはちゃんとハンドラを定義する。*/
    signal(SIGPIPE, SIG_IGN);
 
    /*リッスンソケット作る*/
    sock0 = socket(AF_INET, SOCK_STREAM, 0);
 
    if( sock0 == -1 ){
        perror( "socket error:");
        return errno;
    };
 
 
    on = 1 ;    
    //ReUse可能
    if (setsockopt (sock0, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) <  0) {
        perror( "setsockopt (sock0, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)):");
        return errno ;
    };
    on = 1;
    //KeepAlive
    if(setsockopt (sock0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) < 0) {
        perror( "setsockopt (sock0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)):");
        return errno ;
    };
 
 
    option = KEEPALIVE_DELAY;    //秒後からKeepAliveする
    setsockopt( sock0, IPPROTO_TCP, TCP_KEEPIDLE, (void*)&option, sizeof(option) );
 
    option = KEEPALIVE_INTERVAL;    //秒間隔でKeepAliveする
    setsockopt( sock0, IPPROTO_TCP, TCP_KEEPINTVL, (void*)&option, sizeof(option) );
 
    option =  KEEPALIVE_ERRCOUNT;    //回KeepAlive失敗したらエラーにする
    setsockopt( sock0, IPPROTO_TCP, TCP_KEEPCNT, (void*)&option, sizeof(option) );

以下略

ファイル ファイルの説明
キャプチャ.PNG WireSharkのスクリーンショット
コメント

こんな感じで動いているようです。
accept() する前のソケットで設定してたりしますか?

# 次から、compileできるコードを貼ってもらえると助かります。

#include <stdio.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
 
#define KEEPALIVE_DELAY 2
#define KEEPALIVE_INTERVAL 1
#define KEEPALIVE_ERRCOUNT 3
 
int main()
{
        struct sockaddr_in addr;
        int option = 1;
        int sock0;
        int sock;
        int ret = 0;
 
        sock0 = socket(AF_INET, SOCK_STREAM, 0);
        setsockopt(sock0, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
 
        addr.sin_family = AF_INET;
        addr.sin_port = htons(22222);
        addr.sin_addr.s_addr = INADDR_ANY;
        bind(sock0, (struct sockaddr*) &addr, sizeof(addr));
        listen(sock0, 10);
        sock = accept(sock0, NULL, NULL);
 
        option = 1;
        setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &option, sizeof(option));
 
        option = KEEPALIVE_DELAY;
        setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &option, sizeof(option));
 
        option = KEEPALIVE_INTERVAL;
        setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &option, sizeof(option));
 
        option = KEEPALIVE_ERRCOUNT;
        setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &option, sizeof(option));
 
        while (ret >= 0) {
                ret = recv(sock, NULL, 0, 0);
                if (ret < 0)
                        perror("recv");
        }
 
        return 0;
}

tcpdump の表示

$ sudo tcpdump -n -ilo port 22222
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
14:32:25.377331 IP 127.0.0.1.37552 > 127.0.0.1.22222: Flags [S], seq 1382176984, win 43690, options [mss 65495,sackOK,TS val 86865957 ecr 0,nop,wscale 7], length 0
14:32:25.377365 IP 127.0.0.1.22222 > 127.0.0.1.37552: Flags [S.], seq 96066167, ack 1382176985, win 43690, options [mss 65495,sackOK,TS val 86865957 ecr 86865957,nop,wscale 7], length 0
14:32:25.377382 IP 127.0.0.1.37552 > 127.0.0.1.22222: Flags [.], ack 1, win 342, options [nop,nop,TS val 86865957 ecr 86865957], length 0
14:32:27.401508 IP 127.0.0.1.22222 > 127.0.0.1.37552: Flags [.], ack 1, win 342, options [nop,nop,TS val 86866464 ecr 86865957], length 0
14:32:27.401553 IP 127.0.0.1.37552 > 127.0.0.1.22222: Flags [.], ack 1, win 342, options [nop,nop,TS val 86866464 ecr 86865957], length 0
14:32:29.417504 IP 127.0.0.1.22222 > 127.0.0.1.37552: Flags [.], ack 1, win 342, options [nop,nop,TS val 86866968 ecr 86866464], length 0
14:32:29.417564 IP 127.0.0.1.37552 > 127.0.0.1.22222: Flags [.], ack 1, win 342, options [nop,nop,TS val 86866968 ecr 86865957], length 0

ありがとうございます。
acceptの後でないといけないのですね。

こちらでは
sock0 = socket(AF_INET, SOCK_STREAM, 0);
の後、
setsockopt(sock0, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
の直後に
keepAlive関係の設定も続けてやってました。

Yamamotoです。

横から失礼します。

”ソケット接続が出来なくなる ”件の関連で気になったので投稿しました。

”ソケット接続が出来なくなる ”件で、同じようにAccept前(Socket生成直後)にKeepAliveの設定をしているのですが、Accept前に行っているとソケットが接続できなくなる現象を引き起こしたりすのでしょうか?

Wiresharkで見ると双方からFIN+ACK送信後(双方で切断完了しているはず)にKeepaliveが送信されて、無くなったソケットに接続確認を繰り返してからRST+ACKでリセット送信されています。

あとクライアント側でのconnect接続時も、connect前(Socket生成直後)にKeepalive設定を行っているのですがこれも良くないのでしょうか?

ご意見をお聞かせください。