私は効率的なソケットサーバーを書いています。意図は、全体的なスループットが良好であることです。メインスレッドをリスナーとして使用します。クライアントでasync_accept
あり、ソケットをキューに追加します。ディスパッチャスレッドは、キューから読み取る準備ができているソケットを取得し、ワーカースレッドのキューの1つに追加します。ワーカースレッドのプールを保持しています。ワーカースレッドは実際の読み取り/書き込みを行います。
async_accept
私はリスナーで使用します。どのソケットが読み取りの準備ができているかを確認するために、ディスパッチャでasync_read_someを使用します。このアイデアは機能しますが、問題があります。Myio_service.run()
はlistenerで呼び出されるため、indispatcherのハンドラーasync_read_some
は実際にはリスナースレッドで実行されます。
これが私のコードです:
using boost::asio::ip::tcp;
using namespace std;
std::queue<std::shared_ptr<tcp::socket>> q_sock;
boost::mutex m_log1;
boost::condition_variable m_cond1;
boost::mutex::scoped_lock m_lock1 = boost::mutex::scoped_lock(m_log1);
sem_t _sem_sock;
enum { max_length1 = 1024 };
char data_1[max_length1];
void handle_read1(std::shared_ptr<tcp::socket> sock, const boost::system::error_code& error,
size_t bytes_transferred)
{
printf("handle_read1 : error : %s : %d, thread id is: %ld, pid : %d \n", error.category().name(), error.value(), (long int)syscall(SYS_gettid), getpid());
boost::asio::write(*(sock.get()), boost::asio::buffer(data_1, bytes_transferred));
}
void sock_dispatch() {
int v_size = 0;
std::shared_ptr<tcp::socket> curr_sock;
printf("sock_dispatch started. The ID of this of this thread is: %ld, pid : %d \n", (long int)syscall(SYS_gettid), getpid());
while(1) {
while(1) {
sem_wait(&_sem_sock);
v_size = q_sock.size();
sem_post(&_sem_sock);
if(v_size <= 0)
m_cond1.timed_wait(m_lock1,boost::posix_time::milliseconds(5000));
else
break;
}
sem_wait(&_sem_sock);
curr_sock = q_sock.front();
q_sock.pop();
sem_post(&_sem_sock);
curr_sock->async_read_some(boost::asio::buffer(data_1, max_length1),
boost::bind(handle_read1, curr_sock,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
}
class session
{
public:
session(boost::asio::io_service& io_service)
: sockptr(new tcp::socket(io_service)) {}
void start()
{
printf("START NEW SESSION The ID of this of this thread is: %ld, pid : %d \n", (long int)syscall(SYS_gettid), getpid());
sem_wait(&_sem_sock);
q_sock.push(sockptr);
sem_post(&_sem_sock);
m_cond1.notify_all();
}
std::shared_ptr<tcp::socket> sockptr;
};
class server
{
public:
server(boost::asio::io_service& io_service, short port)
: io_service_(io_service),
acceptor_(io_service, tcp::endpoint(tcp::v4(), port))
{
session* new_session = new session(io_service_);
acceptor_.async_accept(*(new_session->sockptr.get()),
boost::bind(&server::handle_accept, this, new_session,
boost::asio::placeholders::error));
printf("WAITING TO ACCEPT: The ID of this of this thread is: %ld, pid : %d \n", (long int)syscall(SYS_gettid), getpid());
}
void handle_accept(session* new_session,
const boost::system::error_code& error)
{
new_session->start();
new_session = new session(io_service_);
acceptor_.async_accept(*(new_session->sockptr.get()),
boost::bind(&server::handle_accept, this, new_session,
boost::asio::placeholders::error));
}
private:
boost::asio::io_service& io_service_;
tcp::acceptor acceptor_;
};
int main(int argc, char* argv[])
{
sem_init(&_sem_sock, 0, 1);
boost::asio::io_service io_service;
using namespace std;
server s(io_service, atoi(argv[1]));
boost::thread t(boost::bind(sock_dispatch));
io_service.run();
return 0;
}
このコードは、boost :: asioの例、http ://www.boost.org/doc/libs/1_39_0/doc/html/boost_asio/example/echo/async_tcp_echo_server.cppから変更されています。また、クライアントコードはhttp://www.boost.org/doc/libs/1_39_0/doc/html/boost_asio/example/echo/blocking_tcp_echo_client.cppです。
クライアントが接続すると、サーバーの出力は次のようになります。
WAITING TO ACCEPT: The ID of this of this thread is: 3843, pid : 3843
sock_dispatch started. The ID of this of this thread is: 3844, pid : 3843
START NEW SESSION The ID of this of this thread is: 3843, pid : 3843
handle_read1 : error : system : 0, thread id is: 3843, pid : 3843
この場合、ディスパッチャーのスレッドIDは3944ですが、handle_read1はスレッド3843で実行されます。理想的には、handle_read1はディスパッチャーで実行されるため、リスナーでの受け入れがブロックされません。
これを達成するために私が何をすべきか考えていますか?または、全体に対してより良いデザインがあります:)?