如何使用recv()在C ++套接字中收回超过65000字节

我正在使用C ++在Linux中开发客户端服务器应用程序(TCP)。 我想同时发送65,000多个字节。 在TCP中,最大数据包大小只有65,635字节。

我怎样才能无损地发送整个字节?

以下是我在服务器端的代码。

 //Receive the message from client socket if((iByteCount = recv(GetSocketId(), buffer, MAXRECV, MSG_WAITALL)) > 0) { printf("\n Received bytes %d\n", iByteCount); SetReceivedMessage(buffer); return LS_RESULT_OK; } 

如果我使用MSG_WAITALL则需要很长时间来接收字节,所以我怎样才能设置标志接收超过一百万字节的时间。

Solutions Collecting From Web of "如何使用recv()在C ++套接字中收回超过65000字节"

您的问题可能与内核套接字缓冲区大小有关。 尝试添加以下代码:

 int buffsize = 1024*1024; setsockopt(s, SOL_SOCKET, SO_RCVBUF, &buffsize, sizeof(buffsize)); 

您可能还需要增加一些sysctl变量:

 sysctl -w net.core.rmem_max=8388608 sysctl -w net.core.wmem_max=8388608 

请注意,依靠TCP来填充整个缓冲区通常是一个坏主意。 你应该多次调用recv()。 您希望获得超过64K的唯一好理由是提高性能。 但是,Linux应该已经有了自动调整功能,可以根据需要逐步增加缓冲区大小。

从上面的评论来看,似乎你不明白recv是如何工作的,或者它是如何被使用的。

真的想在一个循环中调用recv ,直到你知道预期的数据量已经被接收,或者直到你得到一个“零字节读”的结果,这意味着另一端已经关闭了连接。 总是,没有例外。

如果你需要同时做其他事情(可能是用一个服务器进程!),那么你可能首先需要用pollepoll来检查描述符的准备情况。 这可以让你在套接字准备好的时候多路复用。

你之所以这么做,并没有什么不同,是因为你不知道数据如何被打包以及数据包将如何(或何时)到达。 另外, recv不能保证一次读取的数据量。 它会提供它在你调用的时候的缓冲区中的内容,不多也不少(如果没有任何内容,它可能会阻塞,但是你仍然不能保证当它返回任何特定数量的数据时恢复,它仍然可能会返回例如50个字节!)。

即使只发送总数为5,000字节的数据包,TCP也可以将其分解为5(或10或20)个数据包, recv将返回500(或100或20或1)字节一次,每次你打电话给它。 这就是它的工作原理。
TCP保证你发送的任何东西最终都会到达另一端或者产生一个错误。 而且,它确保无论您发送的是什么到达。 这并不能保证很多其他的东西。 最重要的是,它并不能保证任何特定的数据量在任何给定的时间准备就绪。
你必须为此做好准备,唯一的办法就是多次调用recv 。 否则,在某些情况下,您将永远丢失数据。

MSG_WAITALL原则上应该按照您期望的方式工作,但那是不好的行为,并且不能保证工作。 如果套接字(或网络堆栈中的某个其他结构)运行时遇到软限制或硬限制,则可能不会, 也可能无法满足您的请求。 一些限制也是不明确的。 例如,由于实现细节, SO_RCVBUF的编号必须是您希望在Linux下获得的编号的两倍

服务器应用程序的正确行为不应该依赖于诸如“它适合接收缓冲区”这样的假设。 原则上,您的应用程序需要准备好使用1千字节的接收缓冲区接收兆兆字节的数据,如果需要的话,一次只能处理1个字节的数据块。 一个更大的接收缓冲区将使它更有效率,但就是这样…它仍然必须以任何方式工作。

事实上,你只能看到一些“巨大的”限制的失败只是运气(或者说倒霉的运气)。 它显然“正常工作”的事实表明,你所做的是正确的,但事实并非如此。 它是一个不幸的巧合,它的工作。

编辑:
正如下面的评论所要求的,这是什么样子( 代码明显未经测试,警告空格)。

 std::vector<char> result; int size; char recv_buf[250]; for(;;) { if((size = recv(fd, recv_buf, sizeof(recv_buf), 0)) > 0) { for(unsigned int i = 0; i < size; ++i) result.push_back(recv_buf[i]); } else if(size == 0) { if(result.size() < expected_size) { printf("premature close, expected %u, only got %u\n", expected_size, result.size()); } else { do_something_with(result); } break; } else { perror("recv"); exit(1); } } 

这将会得到你想要的任何数量的数据(或者直到operator new在分配一个向量几百MiB的大小后抛出bad_alloc ,但是这是一个不同的故事…)。

如果你想处理几个连接,你需要添加pollepollkqueue或类似的功能(或… fork ),我将离开这个为读者的练习。

在TCP最大数据包sixe是65,635,字节

不,不是。 TCP是通过IP数据包的分段的字节流协议,并且协议在任何一个连接上具有无限的传输大小。 看看所有这些100MB的下载:你觉得他们怎么工作?

只需发送和接收数据。 你会明白的

我会建议探索kqueue或类似的东西。 通过事件通知,不需要在recv上循环。 只要在EV_READ事件中调用一个简单的读取函数,并在触发事件的套接字上对recv函数使用单个调用即可。 你的函数可以有一个10字节的缓冲区大小,或者你想要的无关紧要,因为如果你第一次没有读完整个消息就会在套接字上得到另一个EV_READ事件, 。 当数据被读取,你会得到一个EOF事件。 没有必要喧闹的循环,可能会或可能不会阻止其他传入的连接。