如何以正确的方式读/写 UNIX 套接字

How to read/write UNIX sockets the right way?

本文关键字:UNIX 套接字 方式读      更新时间:2023-10-16

我想实现这个 bash-命令的功能,它可以读/写到 UNIX 套接字

echo „READ <a command>“ | nc -U /tmp/socket

此命令生成以下输出:

Click::ControlSocket/1.3
200 Read handler 'debug_handler.ping' OK
DATA 0

我当前的 c/c++ 实现如下所示:

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);
}

我只得到这个输出:

Click::ControlSocket/1.3
n=26

下一个 read() 调用不会返回,程序会等待。我尝试了很多方法来读取套接字,结果都相同,所以如果有人能给我一个提示,我做错了什么,那就太好了。

std::string args = "READ <a command>";

服务器正在等待换行符(echo 默认添加一个换行符),因此:

std::string args = "READ <a command>n";

char ret_value[200];
do {
    n = read(sockfd, ret_value, 200);

应该更像

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;

和这条线

    *ret_value+= n;

似乎不清楚 - 您将ret_value的第一个字节增加 n 是什么原因?

尝试类似这样的事情:

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);
}

当然,如果您真的希望输出看起来像原始输出一样,请不要将自己的字符添加到cout(除非出现错误):

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);