简体   繁体   English

接受者和Async_Accept的问题

[英]Acceptor and Problems with Async_Accept

See code. 参见代码。 :PI am able to receive new connections before async_accept() has been called. :PI能够在调用async_accept()之前接收新的连接。 My delegate function is also never called so I can't manage any connections I receive, rendering the new connections useless. 我的委托函数也从未被调用过,因此我无法管理收到的任何连接,从而使新连接无用。 ;) ;)

So here's my question. 所以这是我的问题。 Is there a way to prevent the Boost ASIO acceptor from getting new connections on its own and only getting connections from async_accept()? 有没有一种方法可以防止Boost ASIO接受器自己获取新连接,而仅从async_accept()获取连接?

Thanks! 谢谢!

AlexSocket::AlexSocket(boost::asio::io_service& s): myService(s)
{
    //none at the moment
    connected = false;
    listening = false;

    using boost::asio::ip::tcp;
    mySocket = new tcp::socket(myService);
}

AlexSocket::~AlexSocket()
{
    delete mySocket;
}

bool AlexSocket::StartListening(int port)
{
    bool didStart = false;

    if (!this->listening)
    {
        //try to listen
        acceptor = new tcp::acceptor(this->myService);
        boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), port);
        acceptor->open(endpoint.protocol());
        acceptor->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
        acceptor->bind(endpoint);
        //CAN GET NEW CONNECTIONS HERE (before async_accept is called)
        acceptor->listen();

        didStart = true; //probably change?
        tcp::socket* tempNewSocket = new tcp::socket(this->myService);
        //acceptor->async_accept(*tempNewSocket, boost::bind(&AlexSocket::NewConnection, this, tempNewSocket, boost::asio::placeholders::error) );
    }
    else //already started!
        return false;

    this->listening = didStart;
    return didStart;
}

//this function is never called :(
void AlexSocket::NewConnection(tcp::socket* s, const boost::system::error_code& error)
{
    cout << "New Connection Made" << endl;
    //Start new accept async
    tcp::socket* tempNewSocket = new tcp::socket(this->myService);
    acceptor->async_accept(*tempNewSocket, boost::bind(&AlexSocket::NewConnection, this, tempNewSocket, boost::asio::placeholders::error) );
}

bool AlexSocket::ConnectToServer(std::string toConnectTo, string port)
{
    if (connected)
        return false;

    this->serverConnectedTo = toConnectTo;
    this->serverPort = port;

    ip::tcp::resolver resolver(myService);
    ip::tcp::resolver::query newQuery(toConnectTo, port);
    ip::tcp::resolver::iterator myIter = resolver.resolve(newQuery);
    ip::tcp::resolver::iterator end;

    //error
    boost::system::error_code error = boost::asio::error::host_not_found;

    //try each endpoint
    bool connected = false;
    while (error && myIter != end)
    {
        ip::tcp::endpoint endpoint = *myIter++;
        std::cout << endpoint << std::endl;

        mySocket->close();
        mySocket->connect(*myIter, error);

        if (error)
        {
            //try to connect, if it didn't work return false
            cout << "Did not Connect" << endl << error << endl;
        }
        else
        {
            //was able to connect
            cout << "Connected!" << endl;
            connected = true;
        }
        myIter++;
    }   
    this->connected = connected;
    return connected;
}

EDIT: I've changed my code to reflect what the answers so far have said. 编辑:我已更改代码以反映到目前为止的答案。 I am passing in an io_service to the ctor of my class. 我正在将io_service传递给班级的ctor。 As you can see below, main is NOT calling run on the service, so I would assume that nothing should be able to connect right? 正如您在下面看到的那样,main不会在服务上调用run,因此我认为没有任何内容可以正确连接吗?

I have put my debugger on the listen() line and went to "canyouseeme.org". 我将调试器放在listen()行上,然后转到“ canyouseeme.org”。 Typed in 57422 and hit Connect. 输入57422并单击“连接”。 Couldn't. 不能。 Ran the listen() line. 跑出listen()行。 Was able to connect. 能够连接。 This shouldn't be possible right? 这应该不可能吗? Like never? 像从来没有一样? :( :(

No idea what to do anymore. 不知道该怎么办了。 main() is below. main()在下面。

int main()
{
    boost::asio::io_service s;
    AlexSocket test(s);

    test.StartListening(57422);

    test.ConnectToServer("localhost", "57422");

    cout << "Enter something to quit" << endl;
    int a2;
    cin >> a2;

    return 0;
}

So here's my question. 所以这是我的问题。 Is there a way to prevent the Boost ASIO acceptor from getting new connections on its own and only getting connections from async_accept()? 有没有一种方法可以防止Boost ASIO接受器自己获取新连接,而仅从async_accept()获取连接?

Why do you think this is happening? 您为什么认为这种情况正在发生? If you posted the complete code, that would greatly help. 如果您发布了完整的代码,那将大有帮助。 When I take your snippet and put a boilerplate main and io_service::run() around it, everything works fine. 当我拿起您的代码片段并在其周围放一个样板main和io_service :: run()时,一切正常。

#include <boost/asio.hpp>
#include <boost/bind.hpp>

#include <iostream>

using namespace boost::asio;

class Socket {
public:
    Socket(
            io_service& io_service
          ) :
        _io_service( io_service ),
        _acceptor( new ip::tcp::acceptor(io_service) )
    {

    }

    bool start(int port)
    {
        //try to listen
        ip::tcp::endpoint endpoint(ip::tcp::v4(), port);
        _acceptor->open(endpoint.protocol());
        _acceptor->set_option(ip::tcp::acceptor::reuse_address(true));
        _acceptor->bind(endpoint);
        //CAN GET NEW CONNECTIONS HERE (before async_accept is called)
        _acceptor->listen();

        ip::tcp::socket* temp = new ip::tcp::socket( _io_service );
        _acceptor->async_accept(
                *temp,
                boost::bind(
                    &Socket::NewConnection,
                    this,
                    temp,
                    boost::asio::placeholders::error
                    )
                );
    }

    void NewConnection(
            ip::tcp::socket* s, 
            const boost::system::error_code& error
            )
    {
        std::cout << "New Connection Made" << std::endl;
        //Start new accept async
        ip::tcp::socket* temp = new ip::tcp::socket( _io_service );
        _acceptor->async_accept(
                *temp,
                boost::bind(
                    &Socket::NewConnection, 
                    this,
                    temp,
                    boost::asio::placeholders::error
                    )
                );
    }
private:
    io_service& _io_service;
    ip::tcp::acceptor* _acceptor;
};

int
main()
{
    io_service foo;
    Socket sock( foo );
    sock.start(1234);
    foo.run();

    return 0;
}

compile and run: 编译并运行:

macmini:~ samm$ g++ -lboost_system accept.cc
macmini:~ samm$ ./a.out 
New Connection Made

telnet from another terminal 来自另一个终端的telnet

macmini:~ samm$ telnet 127.0.0.1 1234
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.

I think you are mixing different things here. 我认为您在这里混合了不同的东西。

On the one hand, you are creating a socket for data exchange. 一方面,您正在创建用于数据交换的套接字。 A socket is nothing more than an endpoint of an inter-process communication flow across a computer network. 套接字不过是整个计算机网络上进程间通信流的终结点。 Your boost::asio::tcp::socket uses the TCP-protocoll for the communication; 您的boost :: asio :: tcp :: socket使用TCP-protocoll进行通信; but in general, a socket can use other protocols. 但通常,套接字可以使用其他协议。 For opening a tcp-socket, one uses generally the sequence open-bind-listen-accept on the host. 为了打开tcp套接字,通常使用主机上的序列open-bind-listen-accept。

On the other hand, you analyse the (underlying) TCP-connection. 另一方面,您分析(基础)TCP连接。

So there are two different things here. 所以这里有两件事。 While for the socket the connection is considered "established" only after the "accept" of the host, the underlying TCP-connection is already established after the client connects to a listening socket. 虽然对于套接字来说,仅在主机“接受”之后才认为连接已“建立”,但是在客户端连接到侦听套接字之后,已经建立了基础的TCP连接。 (One the server side, that connection is put on a stack, from which it is dequeue when you call accept()). (在服务器端,该连接放在堆栈上,当您调用accept()时,该连接从队列中出队)。

So the only way to prohibit connection in your case, is not to call listen(). 因此,在您的情况下,禁止连接的唯一方法是调用listen()。

If you are truly getting a new connection at the point when you call acceptor->listen() then I am puzzled by that. 如果在调用acceptor->listen()时确实获得了新的连接,那我会感到困惑。 What are you using to determine whether you've gotten a connection or not? 您正在使用什么来确定是否已建立连接? The io_service is typically quite "reactive" in that it only reacts to events that it has been explicitly told to react to. io_service通常是相当“活跃的”,因为它仅对已明确告知要响应的事件做出响应。

In your example above, the only thing I see that would cause a "new connection" to be initiated is calling async_accept . 在上面的示例中,我看到的唯一会导致“新连接”启动的就是调用async_accept Additionally, what you described makes little sense from a low-level sockets standpoint (using BSD sockets, typically you must call bind , listen , and accept in that order, and only then can a new connection be made). 此外,从低级套接字的角度来看,您所描述的内容毫无意义(使用BSD套接字,通常必须按该顺序调用bindlistenaccept ,然后才能建立新连接)。

My suspicion is that you've actually got some faulty logic somewhere. 我怀疑您实际上在某处有一些错误的逻辑。 Who calls StartListening and how often is it called (it should only need to be called once). 谁调用StartListening以及调用它的频率(应该只调用一次)。 You've gone through a bunch of extra effort to setup your acceptor object that's usually not necessary in Asio - you can typically just use the acceptor constructor to create an acceptor with all the parameters you need, and then just call async_accept : 您已经做了很多额外的工作来设置在Asio中通常不需要的acceptor对象-您通常可以使用acceptor构造函数创建具有所需所有参数的接受器,然后只需调用async_accept

acceptor = new tcp::acceptor(
    this->myService,
    boost::asio::ip::tcp::endpoint(
        boost::asio::ip::tcp::v4(),
        port),
    true);

tcp::socket* tempNewSocket = new tcp::socket(this->myService);
acceptor->async_accept(
    *tempNewSocket, 
    boost::bind(
        &AlexSocket::NewConnection, 
        this, 
        tempNewSocket, 
        boost::asio::placeholders::error) );

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM