Boost Asio async_send produces beep sound - c++

Trying to write a client for a type of server which behaves like an echo server. When I try to send something, it produces a beep sound. I've found that the problem arise at line 356 (on my editor) of win_iocp_socket_service_base.ipp file. The code is:
int result = ::WSASend(impl.socket_, buffers,
static_cast<DWORD>(buffer_count), &bytes_transferred, flags, op, 0);
Then I made some research.
Continuous boost::asio reads here in the comment of the answer, someone said when a binary data is being written to std::cout.
Why does the following code make my computer beep? here, it seems like the problem is same. They concluded that a '\a' is what produced the sound.
Debugging the application, the buffer of the API function I mentioned earlier, contains the following:
"asd#ıııı2•Z\x1aP"
here "asd#" is my string, the rest changes every time when I debug and I don't know what are they. Now, this is probably the part which the sound is produced, but my question how do I prevent it?
I have the following implementation of a one-round "Correspond" function. Note that I also have a isolated Send() function implementation, which can be paired with ReadUntil() explicitly to achieve same result. Using Send() and ReadUntil() together, the beep sound is still produced. Normally, this shouldn't happen as I am not dealing with low-level API functions, but Boost.Asio. Am I doing something wrong?
CODES
void Correspond(const std::string &data,
const std::string &delim,
std::vector<char> &response)
{
std::shared_ptr<std::vector<char>> localbuffer = std::make_shared<std::vector<char>>(data.begin(), data.end());
// pass shared_ptr to callback function to prolong the buffer's lifetime
// !!! perhaps a better buffer management is needed
socket.async_send(boost::asio::buffer(*localbuffer),
std::bind(&TCPClient::on_correspond,
this,
std::placeholders::_1,
std::placeholders::_2,
delim,
std::ref(response),
localbuffer));
}
and following callback implementation
void on_correspond(const boost::system::error_code& errorcode,
std::size_t sent,
const std::string &delim,
std::vector<char> &response,
const std::shared_ptr<std::vector<char>> &buffer)
{
if(errorcode) {
SLOGERROR(mutex, errorcode.message(), "on_correspond()");
}
if(sent == 0) {
SLOG(mutex, "0 bytes sent w/o errors", "on_correspond()");
}
ReadUntil(delim, response);
}
After debugging deep into API, I've found this issue is not related with read function, but I will post it here just to be sure.
void ReadUntil(const std::string &delim, std::vector<char> &response)
{
boost::asio::async_read_until(socket,
buffer,
delim,
std::bind(&TCPClient::on_readuntil,
this,
std::placeholders::_1,
std::placeholders::_2,
std::ref(response)));
}
void on_readuntil(const boost::system::error_code& errorcode,
std::size_t received,
std::vector<char> &response)
{
SLOG(mutex, "on_readuntil invoked", "on_readuntil()");
SLOG(mutex, received, "on_readuntil");
// !!! needs error handling, short-read handling and whatnot
if(errorcode) {
SLOGERROR(mutex, errorcode.message(), "on_readuntil()");
return;
}
if(received == 0) {
SLOG(mutex, "0 bytes received w/o errors", "on_readuntil()");
}
response.reserve(received);
std::copy(boost::asio::buffers_begin(buffer.data()),
boost::asio::buffers_begin(buffer.data()) + received,
std::back_inserter(response));
buffer.consume(received);
}

here "asd#" is my string, the rest changes every time when I debug
The buffer is read without caring about the size of it, welcome to C++. Give the boost::asio::buffer the buffers size.

Related

Sending a large text via Boost ASIO

I am trying to send a very large string to one of my clients. I am mostly following code in HTTP server example: https://www.boost.org/doc/libs/1_78_0/doc/html/boost_asio/examples/cpp11_examples.html
Write callbacks return with error code 14, that probably means EFAULT, "bad address" according to this link:
https://mariadb.com/kb/en/operating-system-error-codes/
Note that I could not use message() member function of error_code to read error message, that was causing segmentation fault. (I am using Boost 1.53, and the error might be due to this: https://github.com/boostorg/system/issues/50)
When I try to send small strings, let's say of size 10 for example, write callback does not return with an error.
Here is how I am using async_write:
void Connection::do_write(const std::string& write_buffer)
{
auto self(shared_from_this());
boost::asio::async_write(socket_, boost::asio::buffer(write_buffer, write_buffer.size()),
[this, self, write_buffer](boost::system::error_code ec, std::size_t transfer_size)
{
if (!ec)
{
} else {
// code enters here **when** I am sending a large text.
// transfer_size always prints 65535
}
});
}
Here is how I am using async_read_some:
void Connection::do_read()
{
auto self(shared_from_this());
socket_.async_read_some(boost::asio::buffer(buffer_),
[this, self](boost::system::error_code ec, std::size_t bytes_transferred)
{
if (!ec)
{
do_write(VERY_LARGE_STRING);
do_read();
} else if (ec != boost::asio::error::operation_aborted) {
connection_manager_.stop(shared_from_this());
}
});
}
What could be causing write callback to return with error with large string?
The segfault indicates likely Undefined Behaviour to me.
Of course there's to little code to tell, but one strong smell is from you using a reference to a non-member as the buffer:
boost::asio::buffer(write_buffer, write_buffer.size())
Besides that could simply be spelled boost::asio::buffer(writer_buffer), there's not much hope that write_buffer stays around for the duration of the asynchronous operation that depends on it.
As the documentation states:
Although the buffers object may be copied as necessary, ownership of the underlying memory blocks is retained by the caller, which must guarantee that they remain valid until the handler is called.
I would check that you're doing that correctly.
Another potential cause for UB is when you cause overlapping writes on the same socket/stream object:
This operation is implemented in terms of zero or more calls to the stream's async_write_some function, and is known as a composed operation. The program must ensure that the stream performs no other write operations (such as async_write, the stream's async_write_some function, or any other composed operations that perform writes) until this operation completes.
If you checked both these causes of concern and find that something must be wrong, please post a new question including a fully selfcontained example (SSCCE or MCVE)

C++ Linux Google Protobuf + boost::asio Cannot Parse

I am trying to send a Google Protobuf message over a boost::asio socket via TCP. I recognize that TCP is a streaming protocol and thus I am performing length-prefixing on the messages before they go through the socket. I have the code working, but it only appears to work some of the time, even though I'm repeating the same calls and not changing the environment. On occasion I will receive the following error:
[libprotobuf ERROR google/protobuf/message_lite.cc:123] Can't parse message of type "xxx" because it is missing required fields: Name, ApplicationType, MessageType
The reason is easy to understand, but I cannot single out why this only occurs sometimes and parses just fine the majority of the time. It is very easy to duplicate the error by just having a single client talking to the server and simply restarting the processes.
Below are the socket code snippets.
const int TCP_HEADER_SIZE = 8;
Sender:
bool Write(const google::protobuf::MessageLite& proto) {
char header[TCP_HEADER_SIZE];
int size = proto.ByteSize();
char data[TCP_HEADER_SIZE + size];
sprintf(data, "%i", size);
proto.SerializeToArray(data+TCP_HEADER_SIZE, size);
boost::asio::async_write(Socket,
boost::asio::buffer(data, TCP_HEADER_SIZE + size),
boost::bind(&TCPSender::WriteHandler,
this, _1, _2));
}
Receiver:
std::array<char, TCP_HEADER_SIZE> Header;
std::array<char, 8192> Bytes;
void ReadHandler(const boost::system::error_code &ec,
std::size_t bytes_transferred) {
if(!ec) {
int msgsize = atoi(Header.data());
if(msgsize > 0) {
boost::asio::read(Socket, boost::asio::buffer(Bytes,static_cast<std::size_t>(msgsize)));
ReadFunc(Bytes.data(), msgsize);
}
boost::asio::async_read(Socket, boost::asio::buffer(Header, TCP_HEADER_SIZE),
boost::bind(&TCPReceiver::ReadHandler, this, _1, _2));
}
else {
std::cerr << "Server::ReadHandler::" << ec.message() << '\n';
}
}
ReadFunc:
void HandleIncomingData(const char *data, const std::size_t size) {
xxx::messaging::CMSMessage proto;
proto.ParseFromArray(data, static_cast<int>(size));
}
I should mention that I need this to be as fast as possible, so any optimizations would be very much appreciated as well.
The program invokes undefined behavior as it fails to meet a lifetime requirement for boost::asio::async_write()'s buffers parameter:
[...] ownership of the underlying memory blocks is retained by the caller, which must guarantee that they remain valid until the handler is called.
Within the Write() function, boost::asio::async_write() will return immediately, and potentially cause data to go out of scope before the asynchronous write operation has completed. To resolve this, consider expanding the life of the underlying buffer, such as by associating the buffer with the operation and performing cleanup in the handler, or making the buffer a data member on TCPSender.

boost read_some function lost data

I'm implementing a tcp server with boost asio library.
In the server, I use asio::async_read_some to get data, and use asio::write to write data. The server code is something like that.
std::array<char, kBufferSize> buffer_;
std::string ProcessMessage(const std::string& s) {
if (s == "msg1") return "resp1";
if (s == "msg2") return "resp2";
return "";
}
void HandleRead(const boost::system::error_code& ec, size_t size) {
std::string message(buffer_.data(), size);
std::string resp = ProcessMessage(message);
if (!resp.empty()) {
asio::write(socket, boost::asio::buffer(message), WriteCallback);
}
socket.async_read_some(boost::asio::buffer(buffer_));
}
Then I write a client to test the server, the code is something like
void MessageCallback(const boost::system::error_code& ec, size_t size) {
std::cout << string(buffer_.data(), size) << std::endl;
}
//Init socket
asio::write(socket, boost::asio::buffer("msg1"));
socket.read_some(boost::asio::buffer(buffer_), MessageCallback);
// Or async_read
//socket.async_read_some(boost::asio::buffer(buffer_), MessageCallback);
asio::write(socket, boost::asio::buffer("msg1"));
socket.read_some(boost::asio::buffer(buffer_), MessageCallback);
// Or async_read
//socket.async_read_some(boost::asio::buffer(buffer_), MessageCallback);
If I run the client, the code will be waiting at second read_some, and output is:resp1.
If I remove the first read_some, the ouput is resp1resp2, that means the server done the right thing.
It seems the first read_some EAT the second response but don't give the response to MessageCallback function.
I've read the quesion at What is a message boundary?, I think if this problem is a "Message Boundary" problem, the second read_some should print something as the first read_some only get part of stream from the tcp socket.
How can I solve this problem?
UPDATE:
I've try to change the size of client buffer to 4, that output will be:
resp
resp
It seems the read_some function will do a little more than read from the socket, I'll read the boost code to find out is that true.
The async_read_some() member function is very likely not doing what you intend, pay special attention to the Remarks section of the documentation
The read operation may not read all of the requested number of bytes.
Consider using the async_read function if you need to ensure that the
requested amount of data is read before the asynchronous operation
completes.
Note that async_read() free function does offer the guarantee that you are looking for
This operation is implemented in terms of zero or more calls to the
stream's async_read_some function, and is known as a composed
operation. The program must ensure that the stream performs no other
read operations (such as async_read, the stream's async_read_some
function, or any other composed operations that perform reads) until
this operation completes.

Timeouts on read and writes

I have been searching for a way to cancel a Boost ASIO read or write operation if it takes over a certain amount of time. My server is sending out HTTP requests, and reading results from those requests, so I originally had coded it as a synchronous read/write, and if it took so long, I would just carry on and ignore the results when they came back. This caused a problem if a server went down, my server would open to many sockets, and would crash. So I decided that I wanted to cancel the read/write if there was too long of a delay, but apparently synchronous read/writes are not able to be canceled without destroying the thread they are running in, which I do not want to do. So I found a post about how to mimic a synchronous read/write with asynchronous calls and cancel a call on time out. This
is the post that I followed. I know this post is fairly old, so I am not sure if function calls have change since that version and the one I am working with(1.48), but this doesn't seem to be working quite right. Here is my code
bool connection::query_rtb(const std::string &request_information, std::string &reply_information)
{
try
{
boost::optional<boost::system::error_code> timer1_result, timer2_result, write_result, read_result;
boost::array<char,8192> buf;
buf.assign(0);
boost::asio::deadline_timer dt(io_service_);
dt.expires_from_now(boost::posix_time::milliseconds(100));
dt.async_wait(boost::bind(&connection::set_result, this, &timer1_result, _1, "timer1"));
boost::asio::async_write(socket_, boost::asio::buffer(request_information, request_information.size()), boost::bind(&connection::set_result, this, &write_result, _1, "write"));
io_service_.reset();
while(io_service_.run_one())
{
if(write_result)
{
dt.cancel();
}
else if(timer1_result)
{
socket_.cancel();
}
}
boost::asio::deadline_timer dt2(io_service_);
dt2.expires_from_now(boost::posix_time::milliseconds(3000));
dt2.async_wait(boost::bind(&connection::set_result, this, &timer2_result, _1, "timer2"));
boost::asio::async_read(socket_, boost::asio::buffer(buf), boost::bind(&connection::set_result, this, &read_result, _1, "read"));
//socket_.async_receive(boost::asio::buffer(buf), boost::bind(&connection::set_result, this, &read_result, _1, "read"));
io_service_.reset();
while(io_service_.run_one())
{
if(read_result)
{
dt2.cancel();
}
if(timer2_result)
{
socket_.cancel();
}
}
reply_information = buf.data();
std::cout << reply_information << std::endl;
return true;
}catch(std::exception& e)
{
std::cerr << e.what() << std::endl;
}
}
void persistent_connection::set_result(boost::optional<boost::system::error_code> *a, boost::system::error_code ec, std::string t)
{
std::cout << t << std::endl;
a->reset(ec);
}
I was wondering if anyone see anything wrong with this code, or has any ideas on why it is not working. Currently the write seems to be fine, however the will not read until after the dt2 is done with it's timer. Please let me know if you need any more information, I will be glad to provide some.
Edit:
Seems like I got it working testing something I thought I previously tested. Using async_receive instead of async_read seems to have fixed whatever problem I was having. Any clue why this would cause I problem? I want to know if there is a problem with my logic or if that is how is async_read will usually act.
boost::array<char,8192> buf;
...
boost::asio::async_read(socket_, boost::asio::buffer(buf), boost::bind(&connection::set_result, this, &read_result, _1, "read"));
You have instructed your program to read 8192 bytes from the socket. If switching the logic from using the async_read() free function to the async_receive() member function resolves this problem, consult the documentation
Remarks
The receive operation may not receive all of the requested number of
bytes. Consider using the async_read function if you need to ensure
that the requested amount of data is received before the asynchronous
operation completes.

Boost ASIO - How to write a console server 2

I'm trying to write a game server to run on Ubuntu Server (No GUI), and I'm having problems right at step 1. I'm new to C++, so please bear with me.
I need to be able to type commands to the server at any given point while it continues running. Since cin is a blocking input, that won't fly. I've dug around and it seems the way to go is to use Boost's ASIO library.
This answer comes incredibly close to fulfilling my needs, but I still need to know two more things:
1: The "command" passed from input seems to be limited to 1 char at a time. I need MUCH more than single key inputs, eg "shutdown", "say 'Hello World!'", "listPlayers -online", etc. I tried adapting the code to use string, instead of char:
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/shared_ptr.hpp>
#include <iostream>
#include <string>
using namespace boost::asio;
class Input : public boost::enable_shared_from_this<Input>
{
public:
typedef boost::shared_ptr<Input> Ptr;
public:
static void create(
io_service& io_service
)
{
Ptr input(
new Input( io_service )
);
input->read();
}
private:
explicit Input(
io_service& io_service
) :
_input( io_service )
{
_input.assign( STDIN_FILENO );
}
void read()
{
async_read(
_input,
boost::asio::buffer( &_command, sizeof(_command) ),
boost::bind(
&Input::read_handler,
shared_from_this(),
placeholders::error,
placeholders::bytes_transferred
));
}
void read_handler(
const boost::system::error_code& error,
size_t bytes_transferred
)
{
if ( error ) {
std::cerr << "read error: " << boost::system::system_error(error).what() << std::endl;
return;
}
if ( _command.compare( "\n" ) != 0 ) {
std::cout << "command: " << _command << std::endl;
}
this->read();
}
private:
posix::stream_descriptor _input;
std::string _command;
};
int main()
{
io_service io_service;
Input::create( io_service );
io_service.run();
}
However, this causes a segmentation error after a few characters of input, and pressing enter after entering any input no longer causes "command: " to appear. Is there a way to have this setup use string? I'm sure appending them to a separate string one character at a time will work, but I'd like to think this setup would work natively with entire strings.
2: (Edited for clarification) I need this non-blocking input to work in tandem with the rest of my server code. The question is: where does that code go? I call your attention to the main() function from above, modified to use a while loop, and call a mainLoop function:
bool loopControl = true;
int main()
{
io_service io_service;
Input::create( io_service );
// This loops continually until the server is commanded to shut down
while( loopControl )
{
io_service.run(); // Handles async input
mainLoop(); // Where my actual program resides
}
}
Even if everything else worked, control still won't ever reach mainLoop() under normal circumstances. In other words, io_service.run() is still blocking, defeating the entire purpose. This obviously isn't the correct way to implement io_service and/or mainLoop(); so what is?
My apologies if this has been done thousands of times, but apparently I'm not Googling the right phrases to bring up the results I'm looking for.
boost::asio::buffer does not directly support creating a mutable-buffer from an std::string, mainly because they are not guaranteed to be continuous in memory pre-C++11.
The way you are call it ((void*, size_t) overload), you will let the read overwrite the internals of std::string, which leads to your segfault. You should probably use one of the other overloads in this list: http://www.boost.org/doc/libs/1_50_0/doc/html/boost_asio/reference/buffer.html - most likely one for std::vector<char>, since you can easily copy that into a string when your read returns.
Now that problem is that you need to know beforehand how many chars you want to read, since your strings are of variable length. For that, you need to async_read the length separately before your read the actual contents. Then you resize the buffer (as I said, most likely std::vector<char>) and schedule a read of that length. Note that the sender can send both together, this is only complicated for reading from a stream... To summerize:
async_read your string length into some integer of fixed length
Resize the buffer for the content read appropriately
async_read your contents
As for your second question, it is not really clear what you want, but you might want to look into io_service::poll() if you want to do your own stuff while asio is running.
boost::asio::buffer( &_command, sizeof(_command) ) means that you want to overwrite 4 first bytes (or whatever sizeof(string) is) of _command object, but this is obviously not what you want. If you need an auto-resizing input buffer, use asio::streambuf instead.
io_service::run blocks the calling thread, so your mainLoop won't run. You can either execute io_service::run in a separate thread, or poll io_serivce manually, interleaving calls to run_one/poll_one (see the reference) with iterations of your own application loop.