real-time writes buffer to the disk when using boost-asio - c++

I have a server which is written with by boost.asio. This server gets the file from the client and write it to disk. I have just a problem with that. When server get the file, it write it to disk when it recieved the file completely. I wanted server write the buffer to disk in real-time fashion. For example, server write to disk every 100kb size of the file it get from the client. I have written the following code but I don't know how can I edited to get to this goal.
void Session::DoReadFileContent(size_t arg_bytes_transferred)
{
if (arg_bytes_transferred > 0)
{
m_outputFile.write(m_buffer.data(), static_cast<std::streamsize>(arg_bytes_transferred));
if (m_outputFile.tellp() >= static_cast<std::streamsize>(m_fileSize))
{
std::cout << "Received file: " << m_fileName << std::endl;
return;
}
}
auto self = shared_from_this();
m_socket.async_read_some(boost::asio::buffer(m_buffer.data(), m_buffer.size()),
[this, self](boost::system::error_code arg_error_code, size_t arg_bytes)
{
DoReadFileContent(arg_bytes);
});
}

First off, in that case it seems better to read explicit sizes of data instead of read_some which reads whatever is available.
In this pattern, it becomes easier to track "remaining bytes receivable" than m_fileSize.
Here's some minor re-shufflings that made your code into a self-contained example. It expects a server to send a line of text giving the payload size and output filename, followed by the contents of that file. An example server can be run with netcat e.g.:
(stat -c '%soutput.dat' main.cpp; cat main.cpp) | netcat -l -p 6969
Live On Coliru
#include <boost/asio.hpp>
#include <fstream>
#include <iostream>
using boost::system::error_code;
using boost::asio::ip::tcp;
struct Session : std::enable_shared_from_this<Session> {
Session(boost::asio::io_context& io, uint16_t port)
: m_socket(io)
{
m_socket.connect({{}, port});
}
void Start();
void DoReadFileContent(size_t transferred = 0);
private:
std::array<char, 1024> m_buffer;
std::streamsize m_remainingSize = 0;
std::string m_fileName = "noname.dat";
std::ofstream m_outputFile;
tcp::socket m_socket;
};
void Session::Start() {
// Reading a size (in text for simplicity) and subsequently receive as many bytes
//
// I'm keeping this sync for simplicity, because you probably already have
// this coded somehwere
boost::asio::streambuf buf;
error_code ec;
auto n = read_until(m_socket, buf, "\n", ec);
std::istream is(&buf);
if (is >> m_remainingSize && getline(is, m_fileName)) {
std::cerr << "Protocol trace: n:" << n << ", fileName:" << m_fileName << " payload_size:" << m_remainingSize << "\n";
m_outputFile.exceptions(std::ios::failbit | std::ios::badbit);
m_outputFile.open(m_fileName, std::ios::binary);
// write excess buffer contents as part of payload
if (buf.size()) {
std::cerr << "Writing " << buf.size() << " bytes\n";
m_remainingSize -= buf.size();
m_outputFile << &buf;
}
DoReadFileContent();
} else {
std::cerr << "Protocol error, payload_size expected\n";
}
}
void Session::DoReadFileContent(size_t transferred) {
if (transferred > 0) {
std::cerr << "Writing " << transferred << " bytes\n";
m_remainingSize -= transferred;
m_outputFile.write(m_buffer.data(), transferred);
}
if (m_remainingSize <= 0) {
std::cout << "Completed file: " << m_fileName << std::endl;
return;
}
auto self = shared_from_this();
auto expect = std::min(size_t(m_remainingSize), m_buffer.size());
std::cout << "Trying to receive next " << expect << " bytes" << std::endl;
async_read(m_socket,
boost::asio::buffer(m_buffer.data(), expect),
[this, self](error_code ec, size_t arg_bytes) {
std::cerr << "async_read: " << ec.message() << " - " << arg_bytes << " bytes\n";
if (!ec) {
DoReadFileContent(arg_bytes);
}
});
}
int main() {
boost::asio::io_context io;
std::make_shared<Session>(io, 6868) // download from port 6868
->Start();
io.run(); // complete
}
Testing with
(stat -c '%soutput.dat' main.cpp; cat main.cpp) | netcat -l -p 6868&
./a.out
md5sum main.cpp output.dat
Prints, e.g.:
Protocol trace: n:15, fileName:output.dat payload_size:2654
Trying to receive next 1024 bytes
async_read: Success - 1024 bytes
Writing 1024 bytes
Trying to receive next 1024 bytes
async_read: Success - 1024 bytes
Writing 1024 bytes
Trying to receive next 606 bytes
async_read: Success - 606 bytes
Writing 606 bytes
Completed file: output.dat
The last two lines
b4eec7203f6a1dcbfbf3d298c7ec0832 main.cpp
b4eec7203f6a1dcbfbf3d298c7ec0832 output.dat
indicate that the received file is identical to the original.
Notes:
packets are delivered in unspecified sizes, on my system e.g. the same file is received as:
Protocol trace: n:15, fileName:output.dat payload_size:2654
Writing 497 bytes
Trying to receive next 1024 bytes
async_read: Success - 1024 bytes
Writing 1024 bytes
Trying to receive next 1024 bytes
async_read: Success - 1024 bytes
Writing 1024 bytes
Trying to receive next 109 bytes
async_read: Success - 109 bytes
Writing 109 bytes
Completed file: output.dat
b4eec7203f6a1dcbfbf3d298c7ec0832 main.cpp
b4eec7203f6a1dcbfbf3d298c7ec0832 output.dat
Note that it starts out with 497 bytes already in the input buffer from the read_until.
The protocol is not secure:
the file names should be validated. Just imagine what happens if the file would be '/home/sehe/myimportant_file.txt' or worse, say /dev/sde1 and we have permissions to do raw block device access...
you might want to specify a amximum size for streambuf, so that if you get a fuzzer that doesn't ever send a '\n' you wouldn't just gobble up all RAM
the error handling on file IO is very rough. I used io exceptions, but you probably want to check for m_outputFile.good() instead at various places

Related

Serial port receives same bytes it just sent

I'm trying to use Boost.Asio to read from and write to a serial port. Here is my code:
void async_read(boost::asio::serial_port& serial_port)
{
auto buffer = std::make_shared<std::vector<uint8_t>>(64);
serial_port.async_read_some(boost::asio::buffer(*buffer),
[buffer, &serial_port](const boost::system::error_code& error, size_t bytes_read)
{
if (error)
{
std::cout << "Error reading serial port: " << error.message() << std::endl;
return;
}
std::string message(buffer->begin(), buffer->end());
std::cout << "Read " << bytes_read << " bytes:\t" << message << std::endl;
async_read(serial_port);
});
}
void async_write(boost::asio::serial_port& serial_port)
{
auto timer = std::make_shared<boost::asio::deadline_timer>(serial_port.get_io_service(), boost::posix_time::seconds(1));
timer->async_wait(
[&serial_port, timer](const boost::system::error_code& error)
{
if (error)
{
std::cout << "Timer error: " << error.message() << std::endl;
return;
}
auto message = std::make_shared<std::string>("Hello\n");
boost::asio::async_write(serial_port, boost::asio::buffer(*message),
[message, &serial_port](const boost::system::error_code& error, size_t bytes_sent)
{
if (error)
{
std::cout << "Error writing to serial port: " << error.message() << std::endl;
return;
}
std::cout << "Wrote " << bytes_sent << " bytes" << std::endl;
async_write(serial_port);
});
});
}
int main()
{
boost::asio::io_service service;
auto serial_port = boost::asio::serial_port(service, "/dev/ttyUSB0");
serial_port.set_option(boost::asio::serial_port::baud_rate(9600));
async_read(serial_port);
async_write(serial_port);
service.run();
}
At the opposite end of the serial cable, I have a separate machine running cat /dev/ttyTHS0.
My issue is that whenever the program performs an async_write, those same bytes are immediately handled by the async_read completion handler - even though the remote machine isn't sending anything.
I'm not sure if the root cause is the code, or because I'm using cat at the other end. When cat is not running, I'm not having the issue.
Running the above code, (with cat /dev/ttyTHS0 at the other end) gives output like this:
Wrote 6 bytes
Read 7 bytes: Hello
Wrote 6 bytes
Read 3 bytes: Hel
Read 4 bytes: lo
Wrote 6 bytes
Read 7 bytes: Hello
Wrote 6 bytes
Read 1 bytes: H
Read 6 bytes: ello
Wrote 6 bytes
Read 7 bytes: Hello
Maybe I'm missing something obvious, but any help is appreciated! Thank you!
This is the expected behaviour for a serial port. These were typically used to connect a terminal like a vt100 to a computer. When you type on the keyboard, the character is sent to the computer, and the serial port echoes it back to the vt100 screen where it is displayed.
If you run stty -a -F /dev/ttyTHS0 on the remote you will see the setting echo is on (before you ran your program on the remote). You can switch it off with stty -echo -F /dev/ttyTHS0, when it will show as -echo.
Typically, when serial ports are used for comms between computers, the application will set the port to raw, noecho. This is to avoid certain translations being done by the serial port driver, so the data arrives unchanged at the application.

UNIX domain socket C++ server can not return data to client

Here are the simple echo server I'm working on, the server will accept the request from client and return what client sends to it. The program works fine with socat, but will freeze when using my own client.
The problem that my old code has is that I use read instead of read_some. read will block the pipe until it reads certain number of bytes or get a broken pipe exception, whereas read_some will read a chunk at a time. The updated version uses read_some to read input stream and check if the last character the program read is \0, if it is \0, that means it reaches the end of command, so it will echo back. This works because I only pass string literals and there is no binary data in the pipe.
The code of the server is
using namespace std;
const char* epStr = "/tmp/socketDemo";
int main() {
namespace local = boost::asio::local;
boost::asio::io_service io_service;
::unlink(epStr);
local::stream_protocol::endpoint ep(epStr);
local::stream_protocol::acceptor acceptor(io_service, ep);
while(1) {
local::stream_protocol::socket *socket = new local::stream_protocol::socket(io_service);
acceptor.accept(*socket);
char buf[2048] = {0};
boost::system::error_code error;
size_t len = 0;
while(1) {
len += socket->read_some(boost::asio::buffer(buf + len, 2048 - len));
cout << "read " << len << endl;
if (buf[len] == '\0') {
break;
}
}
cout << "read " << len << " bytes" << endl;
cout << buf << endl;
boost::asio::write(*socket, boost::asio::buffer(buf, len), boost::asio::transfer_all());
}
}
When testing the server with socat command, for example
echo "12345" | socat - UNIX-CONNECT:/tmp/socketDemo
it will return the desired result.
My client code is
const char* epStr = "/tmp/socketDemo";
int main(int argc, const char* argv[]) {
boost::asio::io_service io_service;
boost::asio::local::stream_protocol::endpoint ep(epStr);
boost::asio::local::stream_protocol::socket socket(io_service);
socket.connect(ep);
boost::asio::write(socket, boost::asio::buffer(argv[1], strlen(argv[1])), boost::asio::transfer_all());
char buf[1024] = {0};
size_t len = 0;
while(1) {
len += socket.read_some(boost::asio::buffer(buf + len, 2048 - len));
std::cout << "read " << len << std::endl;
if (buf[len] == '\0') {
break;
}
}
std::cout << "read " << len << " bytes\n";
std::cout << buf << std::endl;
socket.close();
When execute the client, at first both have no output, after I killed the client, the server will output that it reads n bytes and get a broken pipe exception.
Can this be caused by the read function in the server? If so is there a way to let it know how much data it should read without sending the size of data chunk at the beginning of each message? I am also wondering why socat can work with this server without any problem? Thanks!
I am also wondering why socat can work with this server without any
problem?
Probably because socat closes the socket and your client doesn't.
If so is there a way to let it know how much data it should read
without sending the size of data chunk at the beginning of each
message?
For instance, reading one byte at a time until you read an end-of-message character, assuming that you're defining / using a protocol that includes EOM.

boost::asio error after sending/receiving exactly 128kb

I'm developing a client-server app, both sides of which use boost::asio.
I'm trying to send a large package of data over TCP (356 kb)
On server side, I write like:
boost::asio::async_write(Msocket,
boost::asio::buffer(sendBuffer,dataLen),
boost::bind(&ServerSession::onDataWrite,
this, boost::asio::placeholders::error,
boost::asio::placeholders::bytes_trasferred));
The onDataWrite is simple:
void ServerSession::onDataWrite(const boost::system::error_code& error, const std::size_t bytesSent) {
if (error) {
std::cout << "Error " << error << " while sending data" << std::endl;
}
}
On client side:
int readSize = ...; // defined from msg header, in this case equals 300 kbytes.
boost::asio::async_read(*Msocket,
boost::asio::buffer(recvBuffer, 50*1024*1024),
boost::asio::transfer_exactly(readSize),
boost::bind(&ClientSession::onDataRead,
this, boost::asio::placeholders::error,
boost::asio::placeholders::bytes_trasferred,
readSize));
And onDataRead is:
void ClientSession::onDataRead(const boost::system::error_code& error, const std::size_t bytesRecvd, const int readSize) {
if (error || bytesRecvd != readSize) {
std::cout << "Error " << error << " while getting data, expect " << readSize <<", got " << bytesRecvd << std::endl;
}
}
During write, server side prints
Error system:10014 while sending data
And client prints
Error system:0 while getting data, expect 393216, got 131064
While 131064 = 128kb - 8 bytes of header.
It looks like this 128-kb issue is caused by send/receive buffer overflow. But I though Boost will take care about those buffers itself, transparently for me.
What do I misunderstand?

C++ , return string from function; boost::asio read / write

I get a compile error, additionally I cannot boost::asio::read buf without giving it array elements.
std::string eport::read_data (void)
{
io_service io; // create the I/O service that talks to the serial device
serial_port port (io, PORT); // create the serial device, note it takes the io service and the port name
error_code ec; // address used for error checking
std::string buf [100]; // data with crc on end
try
{
read (port, buffer (buf), ec);
std::cout << "eport::read: result: " << buf << std::endl;
}
catch (error_code &ec)
{
std::cout << "eport::read: ERROR: " << ec << std::endl;
return "error";
}
std::cout << "eport::read: SUCCESS" << std::endl;
return buf;
The error:
eport.cc:83:9: error: could not convert ‘(std::string*)(& buf)’ from ‘std::string* {aka std::basic_string<char>*}’ to ‘std::string {aka std::basic_string<char>}’
Does the function need to be cast as const char* ? I am not sure what is wrong. Any help is appreciated, thank you.
UPDATED CODE
This is my code. I hope it can help someone because asio lacks good examples on the web. I know my write function could be written better, and this code has not been tested so I'm not sure if I'm doing this right or not. Thanks.
#include "../include/main.H"
#include <boost/asio.hpp> // asynchronous input/output
#include <boost/crc.hpp> // cyclic redundancy code (for data checking)
using namespace::boost::system;
using namespace::boost::asio;
const char *PORT = "/dev/ttyS0";
// serial port communication setup
serial_port_base::baud_rate BAUD (9600); // what baud rate do we communicate at (default is 9600)
serial_port_base::character_size C_SIZE (8); // how big is each "packet" of data (default is 8 bits)
serial_port_base::flow_control FLOW (serial_port_base::flow_control::none); // what flow control is used (default is none)
serial_port_base::parity PARITY (serial_port_base::parity::none); // what parity is used (default is none)
serial_port_base::stop_bits STOP (serial_port_base::stop_bits::one); // how many stop bits are used (default is one)
int eport::initialize (void)
{
io_service io; // create the I/O service that talks to the serial device
serial_port port (io, PORT); // create the serial device, note it takes the io service and the port name
// set serial port options
port.set_option (BAUD);
port.set_option (C_SIZE);
port.set_option (FLOW);
port.set_option (PARITY);
port.set_option (STOP);
return 0;
}
int eport::write_data (std::string data)
{
io_service io; // create the I/O service that talks to the serial device
serial_port port (io, PORT); // create the serial device, note it takes the io service and the port name
error_code ec; // address used for error checking
boost::crc_32_type crcresult; // used for communication checking
char buf [1024]; // buffer to hold data
int crc; // holds crc value
std::ostringstream convert; // used to convert int to string
std::string data_crc; // data with crc on end
std::stringstream ss; // used to add strings
strncpy (buf, data.c_str(), sizeof(buf)); // put data into buffer
buf [sizeof(buf) - 1] = 0; // make sure the last element has a null
crcresult.process_bytes (buf, sizeof(buf)); // get crc value from buffer contents
crc = crcresult.checksum(); // put crc value into integer
convert << crc; // convert integer to string
ss << data << convert.str (); // add crc string to data string
data_crc = ss.str (); // data string with crc appended to be used in reading / writing
std::cout << "eport::write: data with crc: " << data_crc << std::endl;
std::cout << "eport::write: writing: " << data_crc << std::endl;
write (port, buffer (data_crc, sizeof(data_crc)), ec); // write data with crc to serial device
if (ec) // if error code is true, print and return
{
std::cout << "eport::write: ERROR: " << ec << std::endl;
return -1;
}
std::cout << "eport::write: SUCCESS" << std::endl;
return crc;
}
std::string eport::read_data (void)
{
io_service io; // create the I/O service that talks to the serial device
serial_port port (io, PORT); // create the serial device, note it takes the io service and the port name
error_code ec; // address used for error checking
streambuf sb; // asio stream buffer to hold read data
std::string buf; // read buffer will be put into this string
size_t transferred = read (port, sb, ec); // read data from serial device
buf.resize (transferred); // resize the string to the read data size
sb.sgetn (&buf[0], buf.size ()); // stores characters from the stream to the array
std::cout << "eport::read: result: " << buf << std::endl;
if (ec)
{
std::cout << "eport::read: ERROR: " << ec << std::endl;
return "error";
}
std::cout << "eport::read: SUCCESS" << std::endl;
return buf;
}
The most generic way would be use a asio::streambuf
streambuf sb;
size_t transferred = read (port, sb, ec);
According to the docs:
This function is used to read a certain number of bytes of data from a stream. The call will block until one of the following conditions is true:
The supplied buffer is full (that is, it has reached maximum size).
An error occurred.
This operation is implemented in terms of zero or more calls to the stream's read_some function.
Then, copy it to a string:
std::string buf;
buf.resize(transferred);
sb.sgetn(&buf[0], buf.size());
Alternatively, preallocate a buffer of the expected size:
std::string buf(100u, '\0');
size_t transferred = read (port, buffer(buf), ec);
buf.resize(transferred);
For more complicated scenarios, use read_until:
streambuf sb;
size_t transferred = read_until(port, sb, "\r\n", ec);
This will read until "\r\n" was encountered (note: may read more than that, but won't invoke read_some again after seeing the delimiter).
Even more complicated stop conditions could use the overload that takes a MatchCondition functor.
Note on exception handling
If you pass ec to receive the error_code there will be no exceptions thrown
buf is an array of std::string. You should change your prototype or return just one string. buf[0] for example.
Most possibly what you want is:
std::string buf; // No [100]
There are issues with your code that you will need to answer, more specifically, how do you know the number of characters that will be sent to your read function?
However, the general answer to your question is to use a character array, and then return this as the std::string:
std::string eport::read_data (void)
{
io_service io; // create the I/O service that talks to the serial device
serial_port port (io, PORT); // create the serial device, note it takes the io service and the port name
error_code ec; // address used for error checking
char buf [100]; // data with crc on end
try
{
read (port, buf, ec);
std::cout << "eport::read: result: " << buf << std::endl;
}
catch (error_code &ec)
{
std::cout << "eport::read: ERROR: " << ec << std::endl;
return "error";
}
std::cout << "eport::read: SUCCESS" << std::endl;
return buf;
}
The std::string constructor will take care of copying the buf at the end to a std::string.
Now, if there is a way to determine the number of characters read, then the function has to be written differently. Most read functions have a parameter specifying the maximum number of characters to read, and somewhere it is returned the number of characters that are read.
Assuming you could rewrite (or call) a different read function that has both of these properties, the code would look like this:
std::string eport::read_data (void)
{
io_service io; // create the I/O service that talks to the serial device
serial_port port (io, PORT); // create the serial device, note it takes the io service and the port name
error_code ec; // address used for error checking
char buf [100]; // data with crc on end
int numCharsRead = 0;
try
{
numCharsRead = read2 (port, buf, 100, ec);
std::cout << "eport::read: result: " << buf << std::endl;
}
catch (error_code &ec)
{
std::cout << "eport::read: ERROR: " << ec << std::endl;
return "error";
}
std::cout << "eport::read: SUCCESS" << std::endl;
return std::string(buf, numCharsRead);
}
Note the difference in the return. A std::string is constructed from the character array, but only up to numCharsRead characters.

Google::protobuf + boost::asio failure

I have studied the existing examples:
Sending Protobuf Messages with boost::asio
Reading Protobuf objects using boost::asio::read_async
Google Protocol Buffers: parseDelimitedFrom and writeDelimitedTo for C++
Are there C++ equivalents for the Protocol Buffers delimited I/O functions in Java?
Sending Protobuf Messages with boost::asio
but I still can not figure out how to pass Google Protobuf messages using the Boost::asio API. In particular I have no clear understanding of the following problems:
Interaction between boost::asio::streambuf and google::protobuf::io objects (and the necessity of the applying of the last ones)
Correct implementation of the message streaming (due to the lack of writeDelimitedTo and parseDelimitedFrom methods in C++ API)
Here is my implementation based on boost::asio v. 1.39 ssl_client from examples.
class client
{
public:
client(boost::asio::io_service& io_service, boost::asio::ssl::context& context,
boost::asio::ip::tcp::resolver::iterator endpoint_iterator)
: socket_(io_service, context),
request_stream(&b),
raw_output(&request_stream),
coded_output(&raw_output)
{
...
}
void handle_connect(const boost::system::error_code& error,
boost::asio::ip::tcp::resolver::iterator endpoint_iterator)
{
...
}
//Debugging function
void print_buffers_condition(const char *step)
{
std::cout << "\nBuffer conditions after " << step << std::endl;
std::cout << "boost::asio::streambuf\t\tb: " << b.size() << std::endl;
std::cout << "google::protobuf::io::OstreamOutputStream raw_output: " << raw_output.ByteCount() << std::endl;
std::cout << "google::protobuf::io::CodedOutputStream coded_output: " << coded_output.ByteCount() << std::endl;
std::cout << std::endl;
}
//Sending test message after SSL Handshake
void handle_handshake(const boost::system::error_code& error)
{
std::cout << "-----------------------------SENDING-----------------------------" << std::endl;
print_buffers_condition("handle handshake");
if (!error)
{
SearchRequest msg;
msg.set_query("qwerty");
msg.set_code(12345);
std::cout << "Debugged" << std::endl;
msg.PrintDebugString();
//Writing the length of the message before and serializing
print_buffers_condition("before serialising");
coded_output.WriteVarint32(msg.ByteSize());
if (!msg.SerializeToCodedStream(&coded_output))
{
std::cout << "serailizing error" << std::endl;
}
else
{
std::cout << "serializing success" << std::endl;
}
//Sending
buffers_condition("before async write");
boost::asio::async_write(socket_,
b,
boost::bind(&client::handle_write, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
buffers_condition("after async write");
}
else
{
std::cout << "Handshake failed: " << error << "\n";
}
}
void handle_write(const boost::system::error_code& error,
size_t bytes_transferred)
{
std::cout << " bytes_trransferred: " << bytes_transferred << std::endl;
if (!error)
{
std::cout << "No error" << std::endl;
...
}
else
{
std::cout << "Write failed: " << error << "\n";
}
}
void handle_read(const boost::system::error_code& error,
size_t bytes_transferred)
{
...
}
private:
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_;
boost::asio::streambuf b;
std::ostream request_stream;
google::protobuf::io::OstreamOutputStream raw_output;
google::protobuf::io::CodedOutputStream coded_output;
};
This code is operational, so after creating the message we fall into the void handle_write(const boost::system::error_code& error, size_t bytes_transferred) function. Printing the bytes_transferred_ value returns 0: server (implemented on the base of examples too) recieves nothing.
The usage of the debugging function void print_buffers_condition(const char *step) hints at loss of message during its transmission through a stack of different buffering objects:
$ ./client 127.0.0.1 5000
-----------------------------SENDING-----------------------------
Buffer conditions after handle handshake
boost::asio::streambuf b: 0
google::protobuf::io::OstreamOutputStream raw_output: 8192
google::protobuf::io::CodedOutputStream coded_output: 0
Debugged:
query: "qwerty"
code: 12345
Buffer conditions after before serialization
boost::asio::streambuf b: 0
google::protobuf::io::OstreamOutputStream raw_output: 8192
google::protobuf::io::CodedOutputStream coded_output: 0
serializing success
Buffer conditions after before async write
boost::asio::streambuf b: 0
google::protobuf::io::OstreamOutputStream raw_output: 8192
google::protobuf::io::CodedOutputStream coded_output: 13
Buffer conditions after after async write
boost::asio::streambuf b: 0
google::protobuf::io::OstreamOutputStream raw_output: 8192
google::protobuf::io::CodedOutputStream coded_output: 13
bytes_trransferred: 0
I have no idea how to do it in a proper way.
OS is RHEL 6.4.
Thank you.
I'm not familiar with asio, but it looks to me like the problem is that you aren't flushing your buffers. The data is stuck in CodedOutputStream and never finds its way into asio.
CodedOutputStream should be allocated on the stack, such that it is destroyed as soon as you're done writing the message. The destructor will flush the buffer. Note that CodedOutputStream is cheap to allocate so there's no performance problem with putting it on the stack (in fact, it's probably better that way).
OstreamOutputStream can similarly be allocated on the stack, but it heap-allocates a buffer which you might want to reuse. If you choose to reuse the same object, make sure to call Flush() to flush the buffer after the CodedOutputStream is destroyed.
Incidentally, OstreamOutputStream is not particularly efficient, because it has to do its own layer of buffering on top of what ostream is already doing. You may want to serialize to a string (str = message.SerializeAsString() or message.SerializeToString(&str)) and then write that directly to the socket (if asio allows this), as it will probably avoid a redundant copy.