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