0

I'm writing server with streaming protocol, so I need to do things like find end of header, copy it and then parse other stuff in boost buffer. As I found out the best way for manipulation with strings (find string in it, copy/delete using iterators and so on) is std::string. But I'm using char array buffer. So I'll need to have two buffers - char array and std::string - every time I'll need to manipulate with buffer I'll need to convert char array to std::string, do my stuff and then convert it back to char array using std::string.c_str(). Another way I found is use streambuf (as I asked in my previous questition) and then create istream/ostream to it and fill content from it to std::string (as showed in documentation). With streambuf I'll need :
streambuf
mutable_buffers_type
istream
ostream
and std::string
But with use of char array and std::string I need just :
char array
std::string

So I think use of streambuf is waste of memory (I need to create buffer for every connection). Can I use std::string as boost buffer ? However I think there may be better way to do this. Can you give me an advice ?

EDIT:

I need to do something like this with my buffer, but char array don't offer features like std::string (erase, substr, ...) so I need to use std::string as buffer. What is the best way to use it as boost::buffer or what is the best way for parsing like this code ?

#include <iostream>

int main(int argc, char* argv[])
{

    //"header" is header
    //"end" is marking that this point is end of header
    //"data" is data after header
    //this all is sent in one packet which I receive to buffer
    //I need to fill "headerend" to std::string header and then remove "headerend" from begining of buffer
    //then continue parsing "data" which stay in buffer

    std::string buffer = "headerenddata"; //I receive something like this
    std::string header; //here I'll fill header (including mark of end of header)

    //find end of header and include also mark of end of header which is "end" (+3)
    int endOfHeader = int(buffer.find("end"))+3; 

    //fill header from buffer to string header
    header = buffer.substr(0, endOfHeader);

    //delete header from input buffer and keep data in it for next parsing
    buffer.erase(buffer.begin(), buffer.begin()+endOfHeader); 
    //will be just "data" becouse header and mark of header are removed
    std::cout << buffer << std::endl; 
    //will be "headerend" which is "header" and mark end of header which is "end"
    std::cout << header << std::endl;


    return 0;
}
Community
  • 1
  • 1
user1307957
  • 541
  • 3
  • 8
  • 19

1 Answers1

3

You can use std::string as a parameter to construct a boost::asio::buffer. I typically use a char vector (std::vector<char>), though. I think it is easier to process it, but that may really depend on how the rest of your code is designed.

You may also use a C++11 array. It behaves similar to a vector, but it statically allocates the space (i.e., the size of underlying buffer cannot change once the array is created). That might give you some performance benefits in some circumstances. If you cannot use C++11, Boost also includes a very similar class.

boost::asio::buffer also accepts a normal char array (char buf[SIZE]), but it might be more convenient to use the previously mentioned options, if possible.

For reference, here it is the documentation for boost::asio::buffer.

Update: In order to avoid the conversion from char[] to string, you could use a vector both for receiving and processing the buffer (using a string for receiving the buffer may also work too, but I have never tried that).

So, for receiving you could do:

vector<char> msg(N);
...
asio::read(socket, asio::buffer(msg), asio::transfer_at_least(N), ec);

Then for processing the packet and splitting the header and the data, you could use iterators, avoiding the operations with O(n) complexity in your code (substr and erase). Of course find (or search in my example) cannot be avoided:

string end_marker = "end";
auto it = search(msg.begin(), msg.end(), end_marker.begin(), end_marker.end());

process_header(msg.begin(), it + 2);
process_data(it + 3, msg.end());
betabandido
  • 18,946
  • 11
  • 62
  • 76
  • You probably didn't understand me. Please check updated questition – user1307957 May 27 '12 at 19:05
  • So your concern are the operations with O(n) complexity you need to do for splitting the header and the data? Besides that, the code looks fine, right? – betabandido May 27 '12 at 19:19
  • Yes, I need to operate with datas in buffer, but char array doesn't offer rich features as std::string. It'll be better if I'll receive data directly to std::string buffer instead of char array. – user1307957 May 27 '12 at 19:42
  • 1
    Can't you use something like: `asio::read(socket, asio::buffer(msg), asio::transfer_at_least(N), ec)`, where `msg` is a `string`? In that way you would not need any translation from `char[]` to `string`. – betabandido May 27 '12 at 19:53
  • I edited my answer, I hope it is more clear now. Let me know, if my solution works for you. – betabandido May 27 '12 at 20:16