0

I'm sure this question has been asked before, and maybe it's just somewhere miles and miles hidden somewhere in Google results or Stackoverflow. But so far I've setup a nonblocking cache server. That does well with small messages or data. But what if the client attempts to send large amounts of data? I've used a delimiter to tell where the packet ends, and before I was using the blocking thread per client setup. After realizing this route isn't reliable due to hardware limitations. So I'm going the single thread approach if possible.

Basically, I want to know how can I do recv that captures packets of data that appends into a single buffer that I can use when the user is done sending data?

One idea I had was simply do a recv like normal. If the delimiter isn't found, then fork the recv in a thread and add up the data in a buffer somewhere.

I.E

struct tempBuffer{
 int socket;
 std::string buffer;
 bool isDone;
};

std::vector<tempBuffer> temp;

...
if !findDelimiter(recvResponseData)
   startThread(collectData, socket);

Here is what my recvAll looks like:

std::string swiss_cache::recvAll(int socket, bool &quit) {

    std::string buffer;
    size_t sentBuffer = 0;
    quit = false;

    //now it is time to receive the page
    while(true)
    {
        char   buf[CHUNK_SIZE+1];
        memset(buf, 0, strlen(buf));
        size_t tmpres = recv(socket, buf, CHUNK_SIZE, 0);

        if(tmpres == 0){
            quit = true;
            return buffer;
        }

        buffer += (const char*)buf;

        if(findEscapeKey(buffer)) {  /* FOUND ESCAPE KEYWORD TO LEAVE RECV */
            return buffer;
        }
    }


    return buffer;

}   /* recvAll */

How can I collect packets of data in a single buffer from a client in a no block mode when the client has to send multiple packets of data?

Fantastic Mr Fox
  • 32,495
  • 27
  • 95
  • 175
ajm113
  • 936
  • 1
  • 8
  • 18

2 Answers2

1

This comes down to the problem of how to handle communication on multiple sockets from within a single thread. The traditional solution is to use the select() or poll() system calls, which take sets of file descriptors of interest, and return with information on which descriptors have data ready for reading.

Using select(), the data handling loop looks like:

Zero read-set of file descriptors.
For each client:
    add client socket to read-set if client not done.

Call select() on read-set.
# read-set now contains file descriptors with pending data

For each file descriptor in the read-set:
    Find the corresponding client.
    Do recv() operation on the file descriptor.
    Update 'done' status for the client if delimiter found.
    Process complete data for the client.

The logic is similar for poll().

halfflat
  • 1,584
  • 8
  • 11
  • Thanks for the help. What I basicly did was change the list/vector from int to a struct that stored the socket id, and had a string buffer. So when ever recv is called, the received data is added to that buffer, till the delimiter has been found. I believe this works better then starting a new thread to collect this data. – ajm113 Mar 07 '15 at 15:43
0

TCP is a streaming protocol. It has no concept of how much data you're expecting, and there's no way to tell when the other end has stopped writing; you just get passed data as it's received. It's up to you to figure out when you have all of the data.

You'll have to keep doing reads and combining what you receive into a single buffer, then operating on it once you have everything you're expecting. It's also important to handle the case where you receive more than you're expecting; if you're sending multiple messages, the final read may contain both the end of one message and the beginning of another.

One common way to figure out how much data you need is to send a header with each message, including how many bytes the message consists of. You can also use a delimiter, like you were thinking, as long as you can guarantee that the delimiter won't appear in the message content.

Collin Dauphinee
  • 13,664
  • 1
  • 40
  • 71
  • Collin, the question wasn’t how to download/upload large data, but how to store the data in a single threaded server correctly (with multiple clients) that keeps appending data to a corresponding buffer till the delimiter has been found for that client. I appreciate the help though. – ajm113 Mar 07 '15 at 15:41