Note that there are some explanatory texts on larger screens.

plurals
  1. POUse stringstream to read from TCP socket
    primarykey
    data
    text
    <p>I am using a socket library (I'd rather not not use it) whose <code>recv</code> operations works with <code>std::string</code>, but is just a wrapper for one call of the <code>recv</code> socket function, so it is probably that I only got some part of the message I wanted. My first instinct was to go in a loop and append the received string to another string until I get everything, but this seems inefficient. Another possibility was to do the same with a char array, but this seems messy. (I'd have to check the strings size before adding into the array and if it overflowed I need to store the string somewhere until the array is empty again.. )</p> <p>So I was thinking about using a stringstream. I use a TLV protocol, so I need to first extract two bytes into an unsigned short, then get a certain amount of bytes from the stringstream and then loop again until I reach a delimiter field.</p> <p>Is there any better way to do this? Am I completely on the wrong track? Are there any best practices? So far I've always only seen direct use of the socket library with char arrays so I'm curious why using `std::string`` with stringstreams could be a bad idea.. </p> <p><strong>Edit:</strong> Replying to the comment below: The library is one we use internally, its not public (its nothing special though, mostly just a wrapper around the socket library to add exceptions, etc.).</p> <p>I should mention that I have a working prototype using the socket library directly. </p> <p>This works something like:</p> <pre><code>int lengthFieldSize = sizeof(unsigned short); int endOfBuffer= 0;//Pointer to last valid position in buffer. while(true) { char buffer[RCVBUFSIZE]; while(true) { int offset= endOfBuffer; int rs= 0; rs= recv(sock, buffer+offset, sizeof(buffer)-offset, 0); endOfBuffer+= rs; if(rs &lt; 1) { // Received nothing or error. break; } else if(endOfBuffer == RCVBUFSIZE) { // Buffer full. break; } else if(rs &gt; 0 &amp;&amp; endOfBuffer &gt; 1) { unsigned short msglength= 0; memcpy((char *) &amp;msglength, buffer+endOfBuffer-lengthFieldSize, lengthFieldSize); if(msglength == 0) { break; // Received a full transmission. } } } unsigned int startOfData = 0; unsigned short protosize= 0; while(true) { // Copy first two bytes into protosize (length field) memcpy((char *) &amp;protosize, buffer+startOfData, lengthFieldSize); // Is the last length field the delimiter? // Then reply and return. (We're done.) // Otherwise: Is the next message not completely in the buffer? // Then break. (Outer while will take us back to receiving) if(protosize == 0) { // Done receiving. Now send: SendReplyMsg(sock, lengthFieldSize); // Clean up. close(sock); return; } else if((endOfBuffer-lengthFieldSize-startOfData) &lt; protosize) { memmove(buffer, buffer+startOfData, RCVBUFSIZE-startOfData); //Adjust endOfBuffer: endOfBuffer-=startOfData; break; } startOfData+= lengthFieldSize; gtControl::gtMsg gtMessage; if(!gtMessage.ParseFromArray(buffer+startOfData, protosize)) { cerr &lt;&lt; "Failed to parse gtMessage." &lt;&lt; endl; close(sock); return; } // Move position pointer forward by one message (length+pbuf) startOfData+= protosize; PrintGtMessage(&amp;gtMessage); } } </code></pre> <p>So basically I have a big loop which contains a receiving loop and a parsing loop. There's a character array being passed back and forth as I can't be sure to have received everything until I actually parse it. I'm trying to replicate this behaviour using "proper" C++ (i.e. std::string)</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload