Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 函数setsockopt似乎不起作用_C++_Sockets_Visual C++_Winsock - Fatal编程技术网

C++ 函数setsockopt似乎不起作用

C++ 函数setsockopt似乎不起作用,c++,sockets,visual-c++,winsock,C++,Sockets,Visual C++,Winsock,我正在使用WinSock2,我希望一次收到我的所有包(它们是XML文件)。 现在我做如下操作,因为setsockopt似乎忽略了我设置接收缓冲区大小的“命令”,但它在执行时总是返回OK: #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

我正在使用WinSock2,我希望一次收到我的所有包(它们是XML文件)。 现在我做如下操作,因为setsockopt似乎忽略了我设置接收缓冲区大小的“命令”,但它在执行时总是返回OK:

#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);
但我想做一些类似的事情(同时):

备注:我的文件小于IP大小。
提前感谢您。

您可以将缓冲区设置为系统允许的最大值,但您所做的任何事情都不允许您同时从TCP接收所有数据。您必须循环,直到收到预期的所有数据

您的问题基于错误的假设。

setsockopt(SO_RCVBUF)
不能保证您可以在一次
recv()
调用中接收整个消息。它甚至不能保证您将获得所请求的缓冲区大小。您必须使用
getsockopt(SO_RCVBUF)
来检索实际的缓冲区大小

SO_RCVBUF
简单地控制套接字在发送方开始阻塞等待您读取字节之前,可以在其内部缓冲区中保存多少字节。但是
recv()
不能保证它将返回您请求的所有字节(除非您使用
MSG_WAITALL
标志调用它,在这种情况下,我不建议使用该标志,因为您事先不知道消息长度)。如果要求
recv()
读取X字节,并且当前只有Y字节可用,其中Yrecv()将返回Y字节,而不是等待返回X字节。唯一的保证是
recv()
将返回至少1个字节,但不超过X个字节。因此,无论您将内部缓冲区大小设置为什么,您仍然需要一个读取循环

SO_RCVBUF
仅仅是一个用于优化网络I/O的建议性选项。实际上,不要将其用于代码的读取逻辑

也就是说,您显示的代码还有其他问题

在循环的每次迭代中,您都在分配和释放接收缓冲区。不要那样做。分配一次,然后循环读取,完成后释放缓冲区

没有必要将接收缓冲区过度分配到超出您实际从
recv()
请求的范围。读取时也不需要将缓冲区归零。这些步骤只是浪费了开销

在将接收缓冲区附加到
std::string
时,也没有考虑到
recv()
的返回值。您正在使用
std::string
构造函数,该构造函数期望缓冲区以null结尾。您依靠缓冲区归零来提供空终止符,但如果数据包含其自身的任何嵌入式nul字符(取决于XML的编码),则这将截断附加到
std::string
的内容
recv()
返回它读取的字节数。您需要在
std::string
中添加足够多的字节,不能多也不能少

尝试类似以下内容:

#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;
}
#定义IP_BUF_SZ 2000000
//...
std::字符串sBuffer;
长时间阅读;
//...
int iBufSize=IP_BUF_SZ;
int iBufVarSize=sizeof(iBufSize);
if(setsockopt(sockfd,SOL_SOCKET,SO_RCVBUF,(char*)和iBufSize,iBufVarSize)=套接字错误)
MessageBox(“无法设置缓冲区大小”);
else if(getsockopt(sockfd,SOL_SOCKET,SO_RCVBUF,(char*)&iBufSize,&iBufVarSize)=套接字错误)
{
MessageBox(“无法获取缓冲区大小”);
iBufSize=IP_BUF_SZ;
}
char*buf=(char*)malloc(iBufSize);
如果(!buf)
MessageBox(“无法分配缓冲区”);
其他的
{
做
{
chrs_read=recv(sockfd,buf,iBufSize,0);

如果(chrs_read),通过检查
recv
函数的返回值,您可以在
while
循环中接收所有数据,并期望在返回值为
0
之前读取,谢谢您的帮助,但还有一个遗留问题:我保留了一个与服务器通信的开放通道(您看到的代码),我每500毫秒发送一个XML。发生的情况是,我的sochet只接收一个XML,因为发送速度太快。因此,简而言之,我的
chrs\u read
返回的
-1
比我应该的要少,并且文件正在连接。@cna正如我在回答的最后一段中告诉你的,在t之间需要一个分隔符XML消息。TCP没有消息边界的概念,您需要在应用层处理它。在循环中调用
recv()
,直到到达消息的适当端,然后根据需要处理消息,然后在循环中调用
recv()
,直到到达下一条消息的适当端,依此类推。
recv()
本身并不能为您做任何事情,您需要自己的逻辑。
#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;
}