简体   繁体   English

函数setsockopt似乎不起作用

[英]Function setsockopt seems not working

I'm working with the WinSock2 and I would like to receive all my packages at once (they are XML files). 我正在使用WinSock2,我想一次接收所有软件包(它们是XML文件)。 Right now I'm making as below because setsockopt seems ignoring my "order" to set a size of the receiving buffer, but it always returns OK from the execution: 现在,我要进行如下操作,因为setsockopt似乎忽略了我设置接收缓冲区大小的“顺序”,但是它总是从执行中返回确定:

#define IP_BUF_SZ 2000000
//...
std::string sBuffer;
long chrs_read = 0;
int iBufSize = IP_BUF_SZ;
//...
if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (char*)&iBufSize, sizeof(int)) == SOCKET_ERROR)
    MessageBox("Unable to increase"); //never reachs here

do
{
    char* buf = (char*)MALLOCZ(IP_BUF_SZ + 1000);
    chrs_read = recv(sockfd, buf, IP_BUF_SZ, 0);

    if (chrs_read > 0)
        sBuffer += std::string(buf);

    FREE(buf);
    buf = NULL;
}
while (chrs_read > 0);

but I would like to do something like that (all at once): 但我想这样做(一次全部):

setsockopt(IP_STATUS[CHAN_EPIC].sockfd, SOL_SOCKET, SO_RCVBUF, (char*)&iBufSize, sizeof(int);
char* buf = (char*)MALLOCZ(IP_BUF_SZ + 1000);
chrs_read = recv(IP_STATUS[CHAN_EPIC].sockfd, buf, IP_BUF_SZ, 0); 
sBuffer += std::string(buf);

Remark : my files are less than IP_BUF_SZ sized. 备注 :我的文件小于IP_BUF_SZ大小。 Thank you in advance. 先感谢您。

setsockopt(SO_RCVBUF) DOES NOT guarantee that you can receive an entire message in a single recv() call. setsockopt(SO_RCVBUF)不保证您可以在单个recv()调用中收到完整的消息。 It DOES NOT even guarantee that you will get the buffer size you requested. 它甚至不保证您将获得所需的缓冲区大小。 You have to use getsockopt(SO_RCVBUF) to retrieve the actual buffer size. 您必须使用getsockopt(SO_RCVBUF)来检索实际的缓冲区大小。

SO_RCVBUF simply controls how many bytes the socket can hold in its internal buffer before the sender starting blocking waiting for you to read the bytes. SO_RCVBUF只是控制套接字在发送方开始阻止等待您读取字节之前可以在其内部缓冲区中保留多少字节。 But recv() DOES NOT guarantee that it will return all of the bytes you requested (unless you call it with the MSG_WAITALL flag, which I would not recommend in this situation since you don't know the message length beforehand). 但是recv()不能保证它将返回您请求的所有字节(除非您使用MSG_WAITALL标志调用它,在这种情况下我不建议这样做,因为您事先不知道消息的长度)。 If you ask recv() to read X bytes, and only Y bytes are currently available, where Y < X, recv() will return Y bytes and not wait to return X bytes. 如果您要求recv()读取X个字节,并且当前仅Y个字节可用,其中Y <X,则recv()将返回Y个字节,而不必等待返回X个字节。 The only guarantee is that recv() will return at least 1 byte and no more than X bytes. 唯一的保证是recv()将返回至少 1个字节且不超过X个字节。 So, you still need a reading loop no matter what you set the internal buffer size to. 因此,无论将内部缓冲区的大小设置为多少,您仍然需要一个读取循环。

SO_RCVBUF is merely a suggestive option used for optimizing network I/O. SO_RCVBUF只是用于优化网络I / O的建议性选项。 Don't actually rely on it for your code's reading logic. 实际上,不要将其用于代码的读取逻辑。

That said, there are other problems with the code you showed. 也就是说,您显示的代码还有其他问题。

You are allocating and freeing your receive buffer on each iteration of your loop. 您正在循环的每次迭代中分配和释放接收缓冲区。 Don't do that. 不要那样做 Allocate it once, THEN loop the reading, THEN free the buffer when finished. 分配一次,然后循环读取,然后在完成后释放缓冲区。

There is no need to over-allocate your receive buffer beyond what you actually ask from recv() . 除了您实际从recv()请求的缓冲区之外,没有必要过度分配接收缓冲区。 There is also no need to zero the buffer when reading. 读取时也无需将缓冲区清零。 Those steps are just wasted overhead. 这些步骤只是浪费在开销上。

You are also not taking the return value of recv() into account when appending the receive buffer to your std::string . 将接收缓冲区附加到std::string时,您也没有考虑recv()的返回值。 You are using the std::string constructor that expects the buffer to be null-terminated. 您正在使用std::string构造函数,该构造函数希望缓冲区以null结尾。 You are relying on your buffer zeroing to provide a null-terminator, but if the data contains any embedded nul characters of its own (depending on the XML's encoding) then that will truncate what you append to the std::string . 您依靠缓冲区归零来提供空终止符,但是如果数据包含其自身的任何嵌入式nul字符(取决于XML的编码),那么它将截断您追加到std::string recv() returns how many bytes it read. recv()返回读取的字节数。 You need to append exactly that many bytes to your std::string , no more no less. 您需要在std::string后面附加那么多字节,不多也不少。

Try something more like this: 尝试更多类似这样的方法:

#define IP_BUF_SZ 2000000

//...

std::string sBuffer;
long chrs_read;

//...

int iBufSize = IP_BUF_SZ;
int iBufVarSize = sizeof(iBufSize);

if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (char*)&iBufSize, iBufVarSize) == SOCKET_ERROR)
    MessageBox("Unable to set buffer size");
else if (getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (char*)&iBufSize, &iBufVarSize) == SOCKET_ERROR)
{
    MessageBox("Unable to get buffer size");
    iBufSize = IP_BUF_SZ;
}

char* buf = (char*) malloc(iBufSize);
if (!buf)
    MessageBox("Unable to allocate buffer");
else
{
    do
    {
        chrs_read = recv(sockfd, buf, iBufSize, 0);
        if (chrs_read <= 0)
        {
            if (chrs_read == SOCKET_ERROR)
                MessageBox("Unable to read message");
            break;
        }
        sBuffer.append(buf, chrs_read);
    }
    while (true);

    free(buf);
    buf = NULL;
}

Note that this logic is reading until the socket disconnects or encounters an error while reading. 请注意,此逻辑一直在读取,直到读取时套接字断开连接或遇到错误为止。 That is OK if there is only ever 1 message per socket connection. 如果每个套接字连接只有1条消息,那就可以了。 But if you intend to send multiple XML messages on a single connection, that will not work anymore. 但是,如果您打算在单个连接上发送多个XML消息,那么它将不再起作用。 You would need to put a delimiter in between the messages so you know where one message ends and the next begins. 您需要在消息之间放置定界符,以便知道一条消息的结束位置和下一条消息的开始位置。 That could be a leading header specifying the message's length, or it could be a unique terminator sequence at the end of the message. 这可以是指定消息长度的前导标头,也可以是消息末尾的唯一终止符序列。

You can make the buffer as big as the system will let you, but nothing you can do will allow you to receive all of your data at once from TCP. 您可以将缓冲区设置为系统允许的最大大小,但是您无能为力,就无法从TCP一次接收所有数据。 You have to loop until you receive all the data you are expecting. 您必须循环播放,直到收到所有期望的数据为止。

Your question is based on a false assumption. 您的问题是基于错误的假设。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM