2011-06-03 173 views
3

我正在寫一個簡單的ProxyServer來分析包並將它們發送到另一個服務器實例,例如,是這樣的:Boost :: Asio:async_read問題

客戶端 - > MYPROXY - >的SQLServer - >
客戶< - MYPROXY < - SQLServer的< -

應該在一個無限循環中運行。 現在我的問題是,代理似乎鬆散包,有時甚至掛起。 當我添加了很多調試信息(寫入控制檯)時,ProxyServer更穩定,爲 。看起來像ProxyServer太快.. :-)

我很確定我做錯了什麼,這裏是我的會話類代碼(代碼是從Boost :: Asio示例派生的)。

#include "session.h" 

#include <iostream> 
using namespace std; 

session::session(boost::asio::io_service& io_service) 
: socket_(io_service) 
, sqlsocket_(io_service) 
, io_service_(io_service) 
, resolver(io_service) 
{ 
    cout << "session::session()" << endl; 
} 

session::~session() 
{ 
    cout << "session::~session()" << endl; 
    cout << "closing session ..." << endl; 
} 

tcp::socket& session::socket() 
{ 
    return socket_; 
} 

void session::start() 
{ 
    cout << "session::start()" << endl; 
    cout << "starting session ..." << endl; 

    // connect to the sqlserver database 
    tcp::resolver::query query("192.168.1.50", "1317"); 
    tcp::resolver::iterator endpoint_iterator = resolver.resolve(query); 
    tcp::endpoint endpoint = *endpoint_iterator; 

    sqlsocket_.async_connect(endpoint, 
     boost::bind(&session::handle_sqlserver_connect, this, 
     boost::asio::placeholders::error, ++endpoint_iterator)); 

    // TODO: connect to the connector 
} 

void session::handle_read(const boost::system::error_code& error, 
          size_t bytes_transferred) 
{ 
    cout << "session::handle_read()" << endl; 
    if (!error) 
    { 
     cout << "session::handle_read() (read: " 
      << bytes_transferred << ")" 
      << endl; 
     boost::asio::async_write(sqlsocket_, 
      boost::asio::buffer(data_, bytes_transferred), 
      boost::bind(&session::handle_sqlserver_write, this, 
      boost::asio::placeholders::error, bytes_transferred)); 
    } 
    else 
    { 
     delete this; 
    } 
} 

void session::handle_sqlserver_read(const boost::system::error_code& error, 
            size_t bytes_transferred) 
{ 
    cout << "session::handle_sqlserver_read()" << endl; 
    if (!error) 
    { 
     cout << "session::handle_sqlserver_read() (read: " 
      << bytes_transferred << ")" 
      << endl; 
     boost::asio::async_write(socket_, 
      boost::asio::buffer(data_, bytes_transferred), 
      boost::bind(&session::handle_write, this, 
      boost::asio::placeholders::error, bytes_transferred)); 
    } 
    else 
    { 
     delete this; 
    } 
} 

void session::handle_write(const boost::system::error_code& error, 
          size_t bytes_transferred) 
{ 
    static int count = 0; 
    cout << ++count << ". session::handle_write()" << endl; 
    if (!error) 
    { 
     cout << "session::handle_write() (read: " 
      << bytes_transferred << ")" 
      << endl; 
     socket_.async_read_some(boost::asio::buffer(data_, max_length), 
      boost::bind(&session::handle_read, this, 
      boost::asio::placeholders::error, 
      boost::asio::placeholders::bytes_transferred)); 
    } 
    else 
    { 
     delete this; 
    } 
} 

void session::handle_sqlserver_write(const boost::system::error_code& error, 
            size_t bytes_transferred) 
{ 
    cout << "session::handle_sqlserver_write()" << endl; 
    if (!error) 
    { 
     cout << "session::handle_sqlserver_write() (read: " 
      << bytes_transferred << ")" 
      << endl; 
     sqlsocket_.async_read_some(boost::asio::buffer(data_, max_length), 
      boost::bind(&session::handle_sqlserver_read, this, 
      boost::asio::placeholders::error, 
      boost::asio::placeholders::bytes_transferred)); 
    } 
    else 
    { 
     delete this; 
    } 
} 

void session::handle_sqlserver_connect(const boost::system::error_code& error, 
             tcp::resolver::iterator endpoint_iterator) 
{ 
    cout << "session::handle_sqlserver_connect()" << endl; 
    if (!error) 
    { 
     socket_.async_read_some(boost::asio::buffer(data_, max_length), 
      boost::bind(&session::handle_read, this, 
      boost::asio::placeholders::error, 
      boost::asio::placeholders::bytes_transferred)); 
    } 
    else if (endpoint_iterator != tcp::resolver::iterator()) 
    { 
     sqlsocket_.close(); 
     tcp::endpoint endpoint = *endpoint_iterator; 
     sqlsocket_.async_connect(endpoint, 
      boost::bind(&session::handle_sqlserver_connect, this, 
      boost::asio::placeholders::error, ++endpoint_iterator)); 
    } 
} 

我是否需要使用其他方法而不是async_ *作爲我的代理類型? 我從我的公司想要重新啓動的一些舊項目移植代碼,但是使用boost而不是以前使用過的Winsock。

任何想法可能是什麼問題?

舊的代碼做了這樣的事情: 與接受方法調用的主要方法創建兩個線程

CreateThread(0, 0, (LPTHREAD_START_ROUTINE)listenatclient, (LPVOID)cs, 0, 0); 
CreateThread(0, 0, (LPTHREAD_START_ROUTINE)listenatserver, (LPVOID)cs, 0, 0); 

和線程調用以下功能:

void listenatclient(LPVOID connection) 
{ 
    connection_s* cs = (connection_s*)connection; 
    char inMessagecli[MSG_SIZE]; 
    int rcount = 0; 

    ... 

    do 
    { 
     memset(inMessagecli, 0, MSG_SIZE); 
     rcount = recv((SOCKET)cs->client, inMessagecli, MSG_SIZE, 0); 
     if (rcount != SOCKET_ERROR) 
     { 
      // analyze package 
      ... 

      send((SOCKET)cs->server, inMessagecli, rcount, 0); 
     } 
    } while (rcount > 0); 
} 

void listenatserver(LPVOID connection) 
{ 
    connection_s* cs = (connection_s*)connection; 
    char inMessageserv[MSG_SIZE]; 
    int rcount = 0; 

    do 
    { 
     memset(inMessageserv, 0, MSG_SIZE); 
     rcount = recv((SOCKET)cs->server, inMessageserv, MSG_SIZE, 0); 
     if (rcount != SOCKET_ERROR) 
     { 
      send((SOCKET)cs->client, inMessageserv, rcount, 0);   
     } 
    } while (rcount > 0); 
} 

[編輯]: 我試着同時爲客戶端和sqlserver運行async_read命令,但是現在我一直在崩潰,有時在boost :: bind中,有時在boost庫的其他部分。

似乎發生的是2或3個連接被創建(3個會話)。在第一次會議結束時,這次事故似乎在第二次會議中發生。

是提升asio不踩踏或我在做一些可怕的錯誤在這裏:-)?

我發佈的代碼爲小訪問代理服務器的位置:

session.h:link

session.cpp:link

server.h:link

server.cpp:link

ProxyServer.cpp:link

+0

session :: data_是什麼類型? – 2011-06-04 01:27:11

+0

你爲什麼要用ASIO混合和匹配'recv()'和'send()'調用?我認爲你需要改變你對recv(2)的錯誤處理,以便它檢查成功,然後假設失敗,並假設唯一的返回碼是'SOCKET_ERROR'。 – Sean 2011-06-04 02:05:39

+0

@Sean我不認爲@user正在混合它們,使用'send'和'recv'的代碼是一些舊的winsock代碼。 – 2011-06-04 14:47:15

回答

4

我懷疑發生了什麼事情是您的一個async_read_some調用正在返回「一些」數據,但不足以讓SQL服務器滿意它已收到完整的請求。您的代碼始終遵循read_from_client - > send_to_server - > read_from_server - > send_to_client的路徑。它不處理您需要read_from_client - > send_to_server - > read_from_client - > send_to_server - > read_from_server - > send_to_client的情況。

您到目前爲止編寫的代碼不會執行與原始操作相同的操作。具體來說,舊代碼正在同時監聽兩個套接字上的讀取。幸運的是,由於您使用的是ASIO,因此您無需混淆線程。只需在兩個套接字上發出同時發出的async_read_some請求,並異步處理它們。

+0

+1我只需要用async_read_some()做同樣的事情。在實現某種請求處理器時,您必須在handle_read()中提供一些處理,以將一個或多個讀取放入完整的請求中。 – Lou 2011-06-04 04:03:03

+0

+1分析不錯,我懷疑這是問題所在。 – 2011-06-04 14:47:47

+0

感謝您的回答,我會嘗試檢查是否有更多數據要從套接字讀取,如果是,請在我的讀取回調方法中處理它。 – user782457 2011-06-13 07:18:02