提升ASIO /协同程序:尝试使用boost asio和coroutines编写echo服务器,但是行为不一致

时间:2014-08-25 23:03:45

标签: c++ windows boost-asio boost-context

在打开许多套接字时,我似乎误解了windows如何处理TIME_WAIT中的套接字。如果有太多人在TIME_WAIT中闲逛,那只是错误。 Linux清理旧的连接并成功(至少在我的盒子上,不知道在哪里记录)。

我正在尝试编写基于协同程序的回显服务器,但它似乎表现得稍微随机。我显然遗漏了一些东西。任何人都可以告诉我,如果我的方法是错误的,如果是的话,我错过了什么?

更新:在linux上测试过(Ubuntu 14.04 / gcc 4.8 / boost 1.56),一切看起来都不错。在Windows上,客户端有时会开始抛出异常(Client Exception: Only one usage of each socket address (protocol/network address/port) is normally permitted)。其他时候运行正常。

更新二:我认为我的代码中出现了一些问题,但是我对Windows网络的理解似乎更成问题。看来,当套接字在Windows上的TIME_WAIT时,即使请求新的套接字超过某个限制,它仍然存在,在Linux上,当请求新套接字时,如果有太多的闲置,它们将被丢弃。

#include <iostream>
#include <thread>
#include <memory>
#include <atomic>

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

using namespace boost::asio::ip;
using namespace boost::asio;
using std::cout;
using std::endl;

std::atomic<int> active;

void echo_server(boost::asio::io_service &svc, int c)
{
    spawn(svc, [&svc, c](yield_context y) {
        try
        {
            tcp::acceptor acceptor(svc, tcp::endpoint(tcp::v4(), 6789));
            for (int i = 0; i < c; i++)
            {
                std::shared_ptr<tcp::socket> s = std::make_shared<tcp::socket>(svc);
                acceptor.async_accept(*s, y);

                spawn(y, [s](yield_context y) mutable {
                    try
                    {
                        streambuf buf;
                        for (;;)
                        {
                            async_read(*s, buf, transfer_at_least(1), y);
                            async_write(*s, buf, y);
                        }
                    }
                    catch (boost::system::system_error &e)
                    {
                        if (e.code() != error::eof)
                            cout << e.what() << endl;
                    }
                });
            }
            cout << "Server Done\n";
        }
        catch (std::exception &e)
        {
            std::cerr << "Server Exception: " << e.what() << std::endl;
        }
    });
}

void echo_client(boost::asio::io_service &svc)
{
    spawn(svc, [&svc](yield_context y) {
        tcp::socket sock(svc);
        try
        {
            async_connect(sock, tcp::resolver(svc).async_resolve(
                tcp::resolver::query("localhost", "6789"), y), y);

            char data[128];
            memcpy(data, "test", 5);
            async_write(sock, buffer(data), y);
            memset(data, 0, sizeof(data));
            async_read(sock, buffer(data), transfer_at_least(1), y);
            if (strcmp("test", data))
                cout << "Error, server is broken\n";

        }
        catch (std::exception &e)
        {
            std::cerr << "Client Exception: " << e.what() << std::endl;
        }

        active--;
    });
}

int main(int argc, char **argv)
{
    io_service svc;
    int c = 10000;
    active = 0;

    // Schedule a server
    echo_server(svc, c);

    // Schedule a bunch of clients, run only 1000 at a time.
    while (c > 0)
    {
        cout << "Remain " << c << endl;
        for (int i = 0; i < 1000; i++)
        {
            echo_client(svc);
        }
        active = 1000;
        while (active > 0)
        {
            if (svc.run_one() == 0) 
            {
                cout << "IO Service reset\n";
                svc.reset();
            }
        }
        c -= 1000;
    }
    svc.run();

    return 0;
}

1 个答案:

答案 0 :(得分:0)

我认为你的司机中有一些无法解释的事情。特别是,你在为什么重置服务?尝试:

int main()
{
    boost::asio::io_service svc;
    int c = 100;

    // Schedule a server
    echo_server(svc, c);

    total_clients = 0;

    // Schedule a bunch of clients
    for (int i = 0; i < c; i++)
    {
        echo_client(svc);
    }

    std::cout << "total_clients: " << total_clients << "\n";
    svc.run();
}

适合我:

total_clients: 100
Done handling new connections