Reputation: 199
I want to implement the functionality of this bash-command that read/write to a UNIX socket:
echo „READ <a command>“ | nc -U /tmp/socket
this command produces the following output:
Click::ControlSocket/1.3
200 Read handler 'debug_handler.ping' OK
DATA 0
My current c/c++ implementation looks something like this:
myprogram.hh
class Myprogram {
public:
Myprogram(int argc, char** argv);
~Myprogram() { };
private:
foo();
int sockfd;
int len;
sockaddr_un address;
};
myprogram.cc
Myprogram::foo() {
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
address.sun_family = AF_UNIX;
strcpy(address.sun_path, "/tmp/socket");
len = sizeof(address);
if(connect(sockfd, (sockaddr*)&address, len) == -1)
return;
std::string args = "READ <a command>";
if (write(sockfd, args.c_str(), sizeof(args.c_str())) == -1){
std::cout << "Error" << std::endl;
return;
}
int n;
char ret_value[200];
do {
n = read(sockfd, ret_value, 200);
std::cout << std::string(ret_value) << std::endl;
std::cout << "n=" << std::to_string(n) << std::endl;
*ret_value+= n;
} while (n > 0);
close(sockfd);
}
I only get this output:
Click::ControlSocket/1.3
n=26
the next read() call doesn‘t return and the program waits. I have tried a lot to read the socket, all with the same result, so it would be great if someone could give me a hint what I'm doing wrong.
Upvotes: 0
Views: 10385
Reputation: 596287
Try something more like this:
Myprogram::foo() {
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sockfd == -1) {
std::cout << "Error" << std::endl;
return;
}
address.sun_family = AF_UNIX;
strcpy(address.sun_path, "/tmp/socket");
if (connect(sockfd, (sockaddr*)&address, sizeof(address)) == -1) {
std::cout << "Error" << std::endl;
close(sockfd);
return;
}
std::string args = "READ <a command>\n";
if (write(sockfd, args.c_str(), args.size())) == -1) {
std::cout << "Error" << std::endl;
close(sockfd);
return;
}
int n;
char ret_value[200];
do {
n = read(sockfd, ret_value, sizeof(ret_value));
if (n < 0) {
std::cout << "Error" << std::endl;
break;
}
if (n == 0) {
break;
}
std::cout.write(ret_value, n) << std::endl;
std::cout << "n=" << n << std::endl;
} while (true);
close(sockfd);
}
Of course, if you really want the output to appear just like the original than don't add your own characters to cout
(except maybe in case of an error):
int n;
char ret_value[200];
do {
n = read(sockfd, ret_value, sizeof(ret_value));
if (n < 0) {
//std::cout << "Error" << std::endl;
break;
}
if (n == 0) {
break;
}
std::cout.write(ret_value, n);
} while (true);
Upvotes: 3
Reputation: 24249
std::string args = "READ <a command>";
the server is waiting for a newline (echo adds one by default), so:
std::string args = "READ <a command>\n";
Also
char ret_value[200];
do {
n = read(sockfd, ret_value, 200);
should be more like
const size_t buflen = 200;
char ret_value[buflen+1];
do {
n = read(sockfd, ret_value, buflen);
if (n < 0)
// error
else
ret_value[n] = 0;
and this line
*ret_value+= n;
seems unclear - you're incrementing the first byte of ret_value by n for what reason?
Upvotes: 3