我使用c ++开发了客户端服务器程序,所以我希望收到超过500kb,我的客户端消息以“!”结束,所以我想收到,直到我的最后一个字节(!)收到, 这是我的代码它不起作用。它有什么问题。
do
{
int num = recv(*csock, buf, bytesLeft,0);
if (num == 0)
{
break;
}
else if (num < 0 && errno != EINTR)
{
fprintf(stderr, "Exit %d\n", __LINE__);
exit(1);
}
else if (num > 0)
{
numRd += num;
buf += num;
bytesLeft -= num;
fprintf(stderr, "read %d bytes - remaining = %d\n", num, bytesLeft);
}
}
while (bytesLeft != 0);
fprintf(stderr, "read total of %d bytes\n", numRd);
答案 0 :(得分:6)
虽然由于你问题的措辞我不确定你的问题是什么,你通常不能使用strcat
附加通过网络收到的原始缓冲区,除非你明确知道它们将是NULL-终止,即便如此,如果您收到意外的数据传输,这并不是真正的“安全”。使用c-strings的假设是它们以NULL结尾,但原始网络缓冲区可能不是,并且使用strcat
将导致您在输入缓冲区未被NULL终止时过度运行。而不是strcat
,使用大小为N字节的已知固定大小的缓冲区来接收数据,并通过缓冲区递增临时指针,直到到达缓冲区的末尾或数据包传输结束。这样,您将始终从网络中读取最多N个字节而不会更多,并防止发生缓冲区溢出情况。
例如,您可以执行以下操作(由于所有复制,这不是最快或更有效的解决方案,但它有效):
unsigned char buf[10000]; //10Kb fixed-size buffer
unsigned char buffer[MAXRECV]; //temporary buffer
unsigned char* temp_buf = buf;
unsigned char* end_buf = buf + sizeof(buf);
do
{
iByteCount = recv(GetSocketId(), buffer,MAXRECV,0);
if ( iByteCount > 0 )
{
//make sure we're not about to go over the end of the buffer
if (!((temp_buf + iByteCount) <= end_buf))
break;
fprintf(stderr, "Bytes received: %d\n",iByteCount);
memcpy(temp_buf, buffer, iByteCount);
temp_buf += iByteCount;
}
else if ( iByteCount == 0 )
{
if(temp_buf != buf)
{
//do process with received data
}
else
{
fprintf(stderr, "receive failed");
break;
}
}
else
{
fprintf(stderr, "recv failed: ");
break;
}
} while(iByteCount > 0 && temp_ptr < end_buf); //check for end of buffer
答案 1 :(得分:1)
在一个连续的字节缓冲区中是否需要所有1MB +的数据?如果是这样,你坚持使用终止'!'的协议并且没有包含长度的标题,那么你会使用memcpy()和realloc()以及std :: vector之类的其他缓冲区类型,这实际上只是做同样的事情。
如果您不需要一个字符串中的所有字节,则可以以其他方式存储它们,例如。 *缓冲区的向量,因此避免复制。
答案 2 :(得分:1)
假设您正在使用阻塞套接字(这是套接字的默认模式),那么recv()
将阻止等待完整MAXRECV
个字节到达。如果客户端发送的字节数少于该字节数,recv()
将阻止等待未到达的数据。
要解决这个问题,您需要:
1)使用1字节缓冲区调用recv()
,调用recv()
直到遇到!
字节。
2)在调用select()
之前调用recv()
以检测套接字实际上何时有要读取的数据,然后调用ioctlsocket(FIONREAD)
以确定实际可以使用{{1}读取多少字节没有阻塞,然后让recv()
读取该字节数。