When you develop socket receive code, you will soon run into the problem that TCP will send data in arbitrary blocks. Even if you send a given string in a single call to send(), that string may arrive as two separate recv() calls -- or may arrive glued together with some previous or following data. Or both.
The following code snippet implements a simple buffer that you can use to receive data, and then pull out lines of text delimited by some character sequence. It will handle re-buffering for you. It is based on std::vector<>, which is, in general, a very handy buffer class, so if you want to apply std::algorithms of other operations on your buffer, you have all the std::vector methods handy.
#if defined(WIN32)
#include <winsock2.h>
#else
#include <sys/socket.h>
#endif
#include <string.h>
#include <string>
#include <vector>
class buffer : public std::vector<char> {
public:
int receive_from_socket(int socket, size_t max_size) {
size_t s = size();
resize(s + max_size);
int r = ::recv(socket, &(*this)[s], max_size, 0);
resize(s + (r < 0) ? 0 : r);
return r;
}
bool get_str_delimited(std::string &out, std::string const &delim) {
if (size() == 0) return false;
if (delim.length() == 0) return false;
push_back(0);
char *str = &(*this)[0];
char *pos = strstr(str, delim.c_str());
pop_back();
if (pos == 0) return false;
out = std::string(str, pos);
erase(begin(), begin() + (pos - str) + delim.length());
return true;
}
};
Usage is simple. When time comes to call recv() on your socket (such as when it is returned readable from select()), call recv_from_socket(), passing in the socket id, and the maximum amount of data you would like to read at a time. Then, repeatedly call get_str_delimited() while it returns true, to extract your lines of text, based on some delimiter string that you pass in. The delimiter text itself will not be included in the returned string.
If you want to just dequeue raw data, then use std::copy() and std::vector::erase(). Note that this buffer is not intended for high-volume binary throughput, though; it is intended to parse lines of text such as found in most ASCII-based internet protocols.