提问者:小点点

是什么原因导致ASYNC_WRITE错误文件描述符?


我正在为客户机服务器应用程序使用boost asio,并遇到了这个问题,这个错误消息并不是那么有信息(至少对我来说是这样)),我将结构作为消息来回发送,从客户机端发送工作非常好,但是从服务器端几乎类似的尝试导致了这个问题(错误):send failed:Bad file descriptor

以下是发送部分的片段(请在评论中询问所需的其他细节):

void read_from_ts(const char*  buf, int len) {  // this is the read callback function
    if (len <= 0) {
        std::cerr << "Error: Connection closed by peer. " << __FILE__ << ":" << __LINE__ << std::endl;
        tcp_client_.close(tcp_connection_);
        tcp_connection_ = nullptr;
        ios_.stop(); // exit
        return;
    }

    const UserLoginRequest *obj = reinterpret_cast<const UserLoginRequest *>(buf);
    int tempId = obj->MessageHeaderIn.TemplateID;
    Responses r;
    switch(tempId)
    {
      case 10018: //login
        const UserLoginRequest *obj = reinterpret_cast<const UserLoginRequest *>(buf);

        //std::cout<<"Login request received"<<"\n";
        boost::asio::ip::tcp::socket sock_(ios_);
        r.login_ack(sock_);

        /*will add more*/
    }

    std::cout << "RX: " << len << " bytes\n";
  }

  class Responses
  {
    public:
      int login_ack(boost::asio::ip::tcp::socket& socket)
      {
        //std::cout<<"here"<<"\n";
        UserLoginResponse info;
        MessageHeaderOutComp mh;
        ResponseHeaderComp rh;

        rh.MsgSeqNum = 0; //no use for now
        rh.RequestTime = 0; //not used at all
        mh.BodyLen = 53; //no use
        mh.TemplateID = 10019; // IMP

        info.MessageHeaderOut = mh;
        info.LastLoginTime  = 0;
        info.DaysLeftForPasswdExpiry = 10; //not used
        info.GraceLoginsLeft = 10; //not used
        rh.SendingTime = 0;
        info.ResponseHeader = rh;
        //Pad6 not used
        async_write(socket, boost::asio::buffer(&info, sizeof(info)), on_send_completed);
      }
      static void on_send_completed(boost::system::error_code ec, size_t bytes_transferred) {
          if (ec)
              std::cout << "Send failed: " << ec.message() << "\n"; //**error shows up here**
          else
              std::cout << "Send succesful (" << bytes_transferred << " bytes)\n";
      }
  };
};

共1个答案

匿名用户

UPDATE在阅读代码时注意到第三个简单的解释,请参阅添加的项目符号

通常当文件描述符在其他地方关闭时。

如果您使用Asio,这通常意味着

>

  • 套接字对象已被销毁。 当代码没有在异步操作期间延长对象的生存期时,这可能是一个初学者错误

    文件描述符被传递给关闭它的其他代码(例如,使用native_handle(https://www.boost.org/doc/libs/1_73_0/doc/html/boost_asio/reference/basic_stream_socket/native_handle.html),其他代码关闭了它(例如,因为它假定所有权并进行了错误处理)。

    更新或者,这可能意味着您的套接字从未初始化为开始。 在您的代码中,我读到:

    //std::cout<<"Login request received"<<"\n";
    boost::asio::ip::tcp::socket sock_(ios_);
    r.login_ack(sock_);
    

    但是,这只是构造一个新的套接字,从不连接或绑定它,而是尝试对它执行login_ack。 这是行不通的,因为login_ack既不绑定也不连接套接字,而是调用它上的async_write

    您的意思是使用tcp_connection_.sock_或类似的文件吗?

    一般来说,在第三方代码中关闭文件描述符在多线程代码中是一个错误,因为它会引起竞争条件,从而导致任意流损坏(例如,请参见如何在可以在另一个线程上关闭的套接字上优雅地选择()?)

    在大多数情况下,您可以改用shutdown

    另外,请注意

    • info没有足够的生存期(在async_write完成之前,它超出了作用域
    • 您的login_ack从不返回值

    在消除上述问题时,这就是我想象的周围代码的样子。

    实际上,由于响应的静态特性,它可能会简单得多,但我不想假设所有响应都那么简单,所以我使用了共享指针生存期:

    住在科里鲁

    #include <boost/asio.hpp>
    #include <boost/core/ignore_unused.hpp>
    #include <iostream>
    using boost::asio::ip::tcp;
    
    struct MyProgram {
        boost::asio::io_context ios_;
    
        struct UserLoginRequest {
            struct MessageHeaderInComp {
                int TemplateID = 10018;
            } MessageHeaderIn;
        };
    
        struct Connection {
            tcp::socket sock_;
            template <typename Executor>
            Connection(Executor ex) : sock_{ex} {}
        };
    
        std::unique_ptr<Connection> tcp_connection_ = std::make_unique<Connection>(ios_.get_executor());
    
        struct {
            void close(std::unique_ptr<Connection> const&);
        } tcp_client_;
    
        struct Responses {
            static auto login_ack() {
                struct UserLoginResponse {
                    struct MessageHeaderOutComp {
                        int BodyLen = 53;             // no use
                        int TemplateID = 10019;       // IMP
                    } MessageHeaderOut;
                    int LastLoginTime  = 0;
                    int DaysLeftForPasswdExpiry = 10; // not used
                    int GraceLoginsLeft = 10;         // not used
                    struct ResponseHeaderComp {
                        int MsgSeqNum = 0;            // no use for now
                        int RequestTime = 0;          // not used at all
                        int SendingTime = 0;
                    } ResponseHeader;
                };
                return std::make_shared<UserLoginRequest>();
            }
        };
    
        void read_from_ts(const char*  buf, int len) {  // this is the read callback function
            if (len <= 0) {
                std::cerr << "Error: Connection closed by peer. " << __FILE__ << ":" << __LINE__ << std::endl;
                tcp_client_.close(tcp_connection_);
                tcp_connection_ = nullptr;
                ios_.stop(); // exit
                return;
            }
    
            const UserLoginRequest *obj = reinterpret_cast<const UserLoginRequest *>(buf);
            int tempId = obj->MessageHeaderIn.TemplateID;
    
            switch(tempId) {
                case 10018: //login
                    const UserLoginRequest *obj = reinterpret_cast<const UserLoginRequest *>(buf);
    
                    //std::cout<<"Login request received"<<"\n";
                    boost::asio::ip::tcp::socket sock_(ios_);
                    auto response = Responses::login_ack();
                    async_write(tcp_connection_->sock_, boost::asio::buffer(response.get(), sizeof(*response)),
                        [response](boost::system::error_code ec, size_t bytes_transferred) {
                            if (ec)
                                std::cout << "Send failed: " << ec.message() << "\n"; //**error shows up here**
                            else
                                std::cout << "Send succesful (" << bytes_transferred << " bytes)\n";
                        });
    
                    /*will add more*/
                    boost::ignore_unused(obj);
            }
    
            std::cout << "RX: " << len << " bytes\n";
          }
    
    };
    
    int main() {
        MyProgram p;
    }
    

    “(或acceptor/POSIX::Strean_Descriptor)