在 C++/STL 中使用 recv 的最优雅的方式?
Most elegant way of using recv in C++ / STL?
到目前为止,我所发现的有关使用套接字 (recv
) 接收数据的所有信息都是在普通的旧 C 语言中。
即使它是 C++,它也会在 std::vector<char>
(呃!)或 defining a static size(例如 vec.resize(BIG_NUMBER)
)上接收 byte-by-byte,然后接收。
然而,所有这些看起来都非常低效和/或丑陋,所以我想知道,在 C++ 中最有效、最正确、最优雅的方法是什么? (不是 C)
Web 浏览器是某人需要接收未知数据量的一个很好的例子。 (为了示例忽略 Content-length
header)
如果您不介意使用第 3 方库,Boost has nice templates for handling sockets in C++. Take a look at the equivalences between plain old C sockets API functions and theirs; and also in this 示例您将了解如何使用 streambufs 避免为接收缓冲区分配内存。
我不知道任何 STL 方法可以这样做,但无论如何,STL 与它无关。
在处理旧的 C API 时,可以简单地用 C++ classes 包装混乱,使外部开发人员看不到实现。
我建议编写包含 SOCKET 作为内部成员的套接字 class,而不是创建一些将 C 包装起来的方法(假设我们谈论流套接字!):
std::string Socket::receive (){
char buffer [SOME_SIZE];
int bytesRead;
std::string receivedData;
do{
bytesRead = recv(socket,buffer,SOME_SIZE-2,0);
buffer [SOME_SIZE-1] ='/0';
receivedData += buffer;
} while (bytesRead != 0 && bytesRead != SOCKET_ERROR );
return receivedData;
}
顺便说一句,我怀疑你可能没有完全理解recv(),recv()填充一个缓冲区,只要你反复调用recv()它就会填充。
套接字接收的字节数不受缓冲区大小的限制。
您可以使用此事实将数据附加到 std::string
基本上,对于每个套接字,您需要有两个用户-space 缓冲区:一个用于发送数据,另一个用于接收。
接收缓冲区的最佳大小与内核缓冲区大小相同。如果您的缓冲区较小 - 您的应用程序执行更多 recv
次调用;如果更大 - 剩余容量可能永远不会被使用。
您使用的有线协议通常具有最大消息大小。您的缓冲区必须至少有那么大。 Bandwidth-delay product 可能还需要调整您的最小缓冲区大小。
通常,您希望将缓冲区与套接字一起分配一次,之后不再调整它们的大小。您可能希望将缓冲区存储为 char[]
、std::array<char>
或 std::vector<char>
(但避免 new char[]
)。
到目前为止,我所发现的有关使用套接字 (recv
) 接收数据的所有信息都是在普通的旧 C 语言中。
即使它是 C++,它也会在 std::vector<char>
(呃!)或 defining a static size(例如 vec.resize(BIG_NUMBER)
)上接收 byte-by-byte,然后接收。
然而,所有这些看起来都非常低效和/或丑陋,所以我想知道,在 C++ 中最有效、最正确、最优雅的方法是什么? (不是 C)
Web 浏览器是某人需要接收未知数据量的一个很好的例子。 (为了示例忽略 Content-length
header)
如果您不介意使用第 3 方库,Boost has nice templates for handling sockets in C++. Take a look at the equivalences between plain old C sockets API functions and theirs; and also in this 示例您将了解如何使用 streambufs 避免为接收缓冲区分配内存。
我不知道任何 STL 方法可以这样做,但无论如何,STL 与它无关。 在处理旧的 C API 时,可以简单地用 C++ classes 包装混乱,使外部开发人员看不到实现。
我建议编写包含 SOCKET 作为内部成员的套接字 class,而不是创建一些将 C 包装起来的方法(假设我们谈论流套接字!):
std::string Socket::receive (){
char buffer [SOME_SIZE];
int bytesRead;
std::string receivedData;
do{
bytesRead = recv(socket,buffer,SOME_SIZE-2,0);
buffer [SOME_SIZE-1] ='/0';
receivedData += buffer;
} while (bytesRead != 0 && bytesRead != SOCKET_ERROR );
return receivedData;
}
顺便说一句,我怀疑你可能没有完全理解recv(),recv()填充一个缓冲区,只要你反复调用recv()它就会填充。 套接字接收的字节数不受缓冲区大小的限制。 您可以使用此事实将数据附加到 std::string
基本上,对于每个套接字,您需要有两个用户-space 缓冲区:一个用于发送数据,另一个用于接收。
接收缓冲区的最佳大小与内核缓冲区大小相同。如果您的缓冲区较小 - 您的应用程序执行更多 recv
次调用;如果更大 - 剩余容量可能永远不会被使用。
您使用的有线协议通常具有最大消息大小。您的缓冲区必须至少有那么大。 Bandwidth-delay product 可能还需要调整您的最小缓冲区大小。
通常,您希望将缓冲区与套接字一起分配一次,之后不再调整它们的大小。您可能希望将缓冲区存储为 char[]
、std::array<char>
或 std::vector<char>
(但避免 new char[]
)。