1

以下のコードで関数setsockopt()をテストしていますが、理解できない動作が発生しています: 以下は、実行中のコード スニペットです ( Ubuntu 12.04 64 ビット、Qt 4.8.x でコンパイル):

#include <QCoreApplication>

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <QDebug>

#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    int sock = ::socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    int res;
    int bufferSizeByte = QString(argv[1]).toInt();

    qDebug() << "Setting socket buffer size to" << bufferSizeByte << "bytes";
    res = setsockopt( sock, SOL_SOCKET, SO_RCVBUF, (void*)&bufferSizeByte, sizeof(bufferSizeByte) );
    if ( -1 == res )
    {
        qDebug() << "ERROR setting socket buffer size to" << bufferSizeByte << "bytes";
    }

    /*
     *  !! WARNING !!
     *  If we try setting the buff size over the kernel max: we do not get an error
     */

    int readValue = 0;
    unsigned int readLen = sizeof(readValue);
    res = getsockopt( sock, SOL_SOCKET, SO_RCVBUF, (void*)&readValue, &readLen );
    if ( -1 == res )
    {
        qDebug() << "ERROR reading socket buffer size";
    }
    else
    {
        qDebug() << "Read socket buffer size:" << readValue << "bytes";
        Q_ASSERT ( readValue == bufferSizeByte*2 );
    }


    return a.exec();
}

基本的に、ソケットの recv バッファー サイズを設定し、それを読み戻して、操作が本当に成功したことを確認します。バッファー サイズを Linux カーネルで構成されている値 ( /proc/sys/net/core/rmem_max ) に設定すると、expecetd として Q_ASSERT() がトリガーされますが、setsockopt エラー メッセージは表示されません。

例えば:

sergio@netbeast: sudo ./setsockopt 300000 
Setting socket buffer size to 300000 bytes  
Read socket buffer size: 262142 bytes  
ASSERT: "readValue == bufferSizeByte*2" in file ../setsockopt/main.cpp, line 43

私が得られないのは、setsockopt() がエラーを返さない理由です。

どんな手掛かり?

4

1 に答える 1

4

の実装sock_setsockopt()(システム コールsetsockopt()がカーネルで最終的に呼び出すもの) には、大きすぎる値を設定してもエラーが発生しない理由についてのコメントがあります。コメントは、その理由が元の BSD 実装との互換性のため (したがって、BSD システム用に作成されたソフトウェアをより簡単に Linux に移植できるようにするため) であることを示しています。

            /* Don't error on this BSD doesn't and if you think
             * about it this is right. Otherwise apps have to
             * play 'guess the biggest size' games. RCVBUF/SNDBUF
             * are treated in BSD as hints
             */

そのときに最大サイズを超えていない場合 (および最小値が満たされている場合)、実際に格納されるのは に渡された値の 2 倍になることに注意してくださいSO_RCVBUFマニュアルページから:

SO_RCVBUF最大ソケット受信バッファーをバイト単位で設定または取得します。を使用して設定すると、カーネルはこの値を 2 倍にし (ブックキーピング オーバーヘッド用のスペースを確保するため) setsockopt(2)、この 2 倍の値が によって返されgetsockopt(2)ます。デフォルト値は/proc/sys/net/core/rmem_defaultファイルによって設定され、最大許容値は/proc/sys/net/core/rmem_maxファイルによって設定されます。このオプションの最小 (2 倍) 値は 256 です。

于 2013-09-08T16:34:47.413 に答える