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.