1

我正在使用以下代码测试函数setsockopt()并且我遇到了我不理解的行为: 下面是我正在运行的代码片段(在 Ubuntu 12.04 64bit、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 ) 中配置的值一致的值会触发 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
             */

请注意,如果这样做时没有超过最大大小(并且如果满足最小值)实际存储的内容是传递给的值的两倍SO_RCVBUF。从手册页

SO_RCVBUF设置或获取最大套接字接收缓冲区(以字节为单位)。当使用 设置它时,内核将这个值加倍(为簿记开销留出空间)setsockopt(2),并且这个加倍的值由getsockopt(2). 默认值由/proc/sys/net/core/rmem_default文件设置,最大允许值由/proc/sys/net/core/rmem_max文件设置。此选项的最小(加倍)值为 256。

于 2013-09-08T16:34:47.413 回答