函数setsockopt似乎不工作
Function setsockopt seems not working
我正在使用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);
但我想做这样的事情(一次):
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);
备注:我的文件小于IP_BUF_SZ大小。
setsockopt(SO_RCVBUF)
不保证您可以在单个recv()
呼叫中接收整个消息。它甚至不能保证你会得到你所请求的缓冲区大小。您必须使用getsockopt(SO_RCVBUF)
来检索实际的缓冲区大小。
SO_RCVBUF
只是控制在发送方开始阻塞等待您读取字节之前套接字可以在其内部缓冲区中保留多少字节。但是recv()
不能保证它会返回你请求的所有字节(除非你用MSG_WAITALL
标志调用它,我不建议在这种情况下,因为你事先不知道消息长度)。如果您要求recv()
读取X字节,而当前只有Y字节可用,则Y <X,>至少 1个字节,并且不超过X个字节。因此,无论将内部缓冲区大小设置为多少,仍然需要一个读循环。
SO_RCVBUF
仅仅是一个用于优化网络I/O的建议选项。不要真正依赖它来实现代码的读取逻辑。
也就是说,您所展示的代码还有其他问题。
在循环的每次迭代中分配和释放接收缓冲区。不要那样做。分配一次,然后循环读取,完成后释放缓冲区。
没有必要过度分配您的接收缓冲区,超出您实际从recv()
请求的缓冲区。读取时也不需要将缓冲区归零。这些步骤只是浪费开销。
在将接收缓冲区附加到std::string
时,您也没有考虑recv()
的返回值。您正在使用std::string
构造函数,该构造函数期望缓冲区以null结束。您依赖于缓冲区归零来提供一个null结束符,但是如果数据包含自己的任何嵌入的null字符(取决于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;
}
注意,这个逻辑一直在读取,直到套接字断开连接或在读取时遇到错误。如果每个套接字连接只有1条消息,这是可以的。但是,如果您打算在单个连接上发送多个XML消息,那么就不再适用了。您需要在消息之间放置一个分隔符,这样您就可以知道一个消息在哪里结束,下一个消息在哪里开始。它可以是指定消息长度的前导头,也可以是消息末尾的唯一结束符序列。
您可以将缓冲区设置成系统允许的最大大小,但是您所做的任何事情都无法让您一次从TCP接收所有数据。你必须循环,直到你收到你想要的所有数据。
你的问题是基于错误的假设。
- QSqlquery prepare()和bindvalue()不工作
- 导入库可以跨dll版本工作吗
- 以螺旋方式打印矩阵的程序.(工作不好)
- 对象指针在c++中是如何工作的
- 为什么在Windows上的VS 2019和Clang 9中"size_t"在没有标题的情况下工作
- VSOMEIP-2个设备之间的通信(TCP/UDP)不工作
- 为字符串中每 N 个字符插入空格的函数没有按照我认为的方式工作?
- C++为线程工作动态地分割例程
- 为什么我的 std::ref 无法按预期工作?
- 布尔比较运算符是如何在C++中工作的
- SampleConsensusPrerejective(ext.RANSAC)是如何真正工作的
- 不确定要在我的main中放入什么才能使我的代码正常工作
- 为什么std::condition_variable notify_all的工作速度比notify_one快(对于随机请
- <<操作员在下面的行中工作
- 有人能解释一下为什么下界是这样工作的吗C++的
- ExtractIconEx:可以工作,但偶尔会崩溃
- C++中的memset函数工作不正常
- 当我在第一个循环中使用"auto"时,它工作正常,但是使用"int"它会给出错误,为什么?
- 链表c++插入,所有情况都已检查,但没有任何工作
- 函数setsockopt似乎不工作