UNIX 域套接字 C++ 服务器无法 return 数据到客户端

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

这是我正在处理的简单回显服务器,服务器将接受来自客户端的请求以及 return 客户端发送给它的请求。该程序在 socat 上运行良好,但在使用我自己的客户端时会冻结。

我的旧代码存在的问题是我使用 read 而不是 read_someread 将阻塞管道,直到它读取一定数量的字节或出现管道异常,而 read_some 将一次读取一个块。更新版本使用read_some读取输入流,检查程序读取的最后一个字符是否为[=20=],如果是[=20=],则表示到达命令结尾,因此它将回声。这是有效的,因为我只传递字符串文字并且管道中没有二进制数据。

服务器代码为

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] == '[=11=]') {
          break;
        }
      }

    cout << "read " << len << " bytes" << endl;
    cout << buf << endl;

    boost::asio::write(*socket, boost::asio::buffer(buf, len), boost::asio::transfer_all());
  }
}

使用socat命令测试服务器时,例如

echo "12345" | socat - UNIX-CONNECT:/tmp/socketDemo

它会 return 想要的结果。

我的客户端代码是

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] == '[=13=]') {
        break;
      }
    }

  std::cout << "read " << len << " bytes\n";

  std::cout << buf << std::endl;

  socket.close();

执行client时,一开始两者都没有输出,我kill client后,server会输出读取n个字节,出现broken pipe异常

会不会是服务器中的read函数引起的?如果是这样,有没有办法让它知道应该读取多少数据而不在每条消息的开头发送数据块的大小?我也想知道为什么 socat 可以毫无问题地使用此服务器?谢谢!

I am also wondering why socat can work with this server without any problem?

可能是因为 socat 关闭了套接字而您的客户端没有。

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?

例如,假设您正在定义/使用包含 EOM 的协议,一次读取一个字节,直到读取 end-of-message 个字符。