-2

ブースト asio ライブラリを使用して http クライアントを実装しようとしています。しかし、修正できないリンカ エラーに直面しています。

ここにコードがあります

yql_asio.cpp

#include "common.h"
#include "yql.h"

int main(int argc, char* argv[])
{
    try
    {
        int thread_num = 2;
        if ( argc > 1 )
            thread_num = boost::lexical_cast<int>(argv[1]);


        boost::asio::io_service io_service;

        Yql yql_main(io_service, "http://www.google.com");
        yql_main.GetResponse();

        io_service.run();

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

    return 0;

}

yql.h

#ifndef YQL_H
#define YQL_H

#include "yql_conn.h"
#include "common.h"

typedef std::deque<io_service_ptr> ios_deque;

class Yql //: public boost::noncopyable
{
private:
    std::string m_url;
    std::string m_response;
    //boost::shared_ptr<Connection> m_conn;
    Connection *m_conn;
    boost::asio::io_service &io_service_;

public:
    Yql(boost::asio::io_service &io_service, std::string p_url);
    ~Yql(){}
    void GetResponse();
};


#endif

yql.cpp

#include "yql.h"


Yql::Yql(boost::asio::io_service& io_services, std::string p_url) 
    : m_url(p_url)
    , io_service_(io_services)
{
    m_conn = new Connection(io_service_, p_url);
    //m_conn = Connection::create(io_service_, m_url);
}

void Yql::GetResponse()
{
    m_conn->start();
}

yql_conn.h

#ifndef YQL_CONN_H
#define YQL_CONN_H

#include "common.h"
#include <map>

class Connection //: public boost::enable_shared_from_this<Connection>
{
public:
    typedef boost::shared_ptr<Connection> pointer;

    static pointer create(ba::io_service & io_service, std::string p_url)
    {
        return pointer(new Connection(io_service, p_url));
    }

    Connection(ba::io_service & io_service, std::string p_url);

    /*ba::ip::tcp::socket& socket()
    {
        return socket_;
    } */

    void start();

private:

    /*void handle_browser_write(const bs::error_code & errc, size_t len);*/
    void handle_read_headers(const bs::error_code & errc, size_t len);
    void handle_server_write(const bs::error_code & errc, size_t len);
    void handle_server_read_headers(const bs::error_code & errc, size_t len);
    void handle_server_read_body(const bs::error_code & errc, size_t len);

    void start_connect();
    void start_write_to_server();
    void shutdown();

    void handle_resolve(const boost::system::error_code & err, ba::ip::tcp::resolver::iterator endpoint_iterator);
    void handle_connect(const boost::system::error_code & err, ba::ip::tcp::resolver::iterator endpoint_iterator);

    ba::io_service& io_service_;
    ba::ip::tcp::socket socket_;
    ba::ip::tcp::resolver resolver_;
    //bool proxy_closed;
    //bool isPersistent;
    int32_t RespLen;
    int32_t RespReaded;

    //boost::array<char, 8192> bbuffer;
    boost::array<char, 8192> sbuffer;

    std::string m_response;

    std::string m_url;
    std::string m_headers;
    std::string m_new_url;
    std::string m_method;
    std::string m_req_version;
    std::string m_server;
    std::string m_port;
    //bool m_is_open;

    std::string fReq;

    typedef std::map<std::string, std::string> headersMap;
    headersMap reqHeaders, respHeaders;

    void parseHeaders(const std::string& h, headersMap& m);
};


#endif

yql_conn.cpp

#include "yql_conn.h"

Connection::Connection(ba::io_service & io_service, std::string p_url)
    : io_service_(io_service)
    , socket_(io_service)
    , resolver_(io_service)
    //, proxy_closed(false)
    //, isPersistent(false)
    //, m_is_open(false)
    , m_url(p_url)
{
} //end of Connection()


void Connection::start() //called
{
    std::cout<<__FUNCTION__<<"BEGINS"<<std::endl;

    m_headers.clear();
    reqHeaders.clear();
    respHeaders.clear();

    start_connect();

    //boost::asio::async_read(bsocket_, ba::buffer(bbuffer), ba::transfer_at_least(1),
    //  boost::bind(&Connection::handle_browser_read_headers,
    //              shared_from_this(),
    //              ba::placeholders::error,
    //              ba::placeholders::bytes_transferred) );

    std::cout<<__FUNCTION__<<"ENDS"<<std::endl;
} //start() 


void Connection::start_connect() //called
{
    std::cout<<__FUNCTION__<<"BEGINS"<<std::endl;
    m_server = "";
    //std::string port = "80";
    m_port = "80";
    boost::regex rHTTP("http://(.*?)(:(\\d+))?(/.*)");
    boost::smatch m;

    if ( boost::regex_search(m_url, m, rHTTP, boost::match_extra) )
    {
        m_server = m[1].str();
        if ( m[2].str() != "" )
        {
            m_port = m[3].str();
        }
        m_new_url = m[4].str();
    }

    if ( m_server.empty() )
    {
        std::cout<<"Can't parse URL "<<std::endl;
        return;
    }

    //if ( !m_is_open || (server != m_server) || (port != m_port) )
    /*if ( port != m_port) )
    {
        m_server = server;
        m_port = port;
    */  
    boost::asio::ip::tcp::resolver::query query(m_server, m_port);

    resolver_.async_resolve(query, 
        boost::bind(&Connection::handle_resolve, this,//shared_from_this(),
            boost::asio::placeholders::error,
            boost::asio::placeholders::iterator));
    //}
    /*else
    {
        start_write_to_server();
    }*/

    std::cout<<__FUNCTION__<<"ENDS"<<std::endl;
}//start_connect() 


void Connection::handle_resolve(const boost::system::error_code & err,
                                    boost::asio::ip::tcp::resolver::iterator endpoint_iterator) //called
{
    std::cout<<__FUNCTION__<<"BEGINS"<<std::endl;
    if ( !err )
    {
        std::cout<<"Remote address resolved..."<<std::endl;
        boost::asio::ip::tcp::endpoint endpoint = *endpoint_iterator;
        socket_.async_connect(endpoint, boost::bind(&Connection::handle_connect,
                                            //shared_from_this(),
                                            this,
                                            boost::asio::placeholders::error,
                                            ++endpoint_iterator));
    }
    else
    {
        shutdown();
    }
    std::cout<<__FUNCTION__<<"ENDS"<<std::endl;
} //handle_resolve()


void Connection::handle_connect(const boost::system::error_code & err, 
                boost::asio::ip::tcp::resolver::iterator endpoint_iterator) //called
{
    std::cout<<__FUNCTION__<<"BEGINS"<<std::endl;

    if ( !err )
    {
        boost::asio::ip::tcp::endpoint remote_host = socket_.remote_endpoint();
        boost::asio::ip::address remote_host_addr = remote_host.address();
        std::string addr_repr = remote_host_addr.to_string();
        std::cout<<"Connected to "<<addr_repr<<std::endl;
        //m_is_open = true;
        start_write_to_server();
    }
    else if ( endpoint_iterator != boost::asio::ip::tcp::resolver::iterator())
    {
        socket_.close();
        boost::asio::ip::tcp::endpoint endpoint = *endpoint_iterator;
        socket_.async_connect(endpoint, boost::bind(&Connection::handle_connect, 
                                //shared_from_this(),
                                this,
                                boost::asio::placeholders::error,
                                ++endpoint_iterator));
    }
    else
    {
        shutdown();
    }

    std::cout<<__FUNCTION__<<"ENDS"<<std::endl;
} //handle_connect()


void Connection::start_write_to_server() //called
{
    std::cout<<__FUNCTION__<<"BEGINS"<<std::endl;

    fReq = m_method;
    fReq += " ";
    //fReq += m_new_url;
    fReq += m_url;
    fReq += " HTTP/";
    fReq += "1.0";
    fReq += "\r\n";
    fReq += m_headers;

    boost::asio::async_write(socket_, boost::asio::buffer(fReq),
        boost::bind(&Connection::handle_server_write, this, //shared_from_this(), 
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred));

    m_headers.clear();

    std::cout<<__FUNCTION__<<"ENDS"<<std::endl;
} //start_write_to_server()


void Connection::handle_server_write(const bs::error_code & err, size_t len) //called
{
    std::cout<<__FUNCTION__<<"BEGINS"<<std::endl;

    if ( !err )
    {
        std::cout<<"Bytes sent to server :: "<<len<<std::endl;
        boost::asio::async_read(socket_, boost::asio::buffer(sbuffer), boost::asio::transfer_at_least(1),
            boost::bind(&Connection::handle_server_read_headers,
                        //shared_from_this(),
                        this,
                        boost::asio::placeholders::error,
                        boost::asio::placeholders::bytes_transferred ) );
    }
    else
    {
        shutdown();
    }

    std::cout<<__FUNCTION__<<"ENDS"<<std::endl;
} //handle_server_write


void Connection::handle_server_read_headers(const boost::system::error_code & err, size_t len) //called
{
    std::cout<<__FUNCTION__<<"BEGINS"<<std::endl;

    if ( !err )
    {
        std::string::size_type idx;

        if ( m_headers.empty() )
            m_headers = std::string(sbuffer.data(), len);
        else
            m_headers += std::string(sbuffer.data(), len);

        idx = m_headers.find("\r\n\r\n");

        if ( idx == std::string::npos )
        {
            boost::asio::async_read(socket_, boost::asio::buffer(sbuffer),
                                        boost::asio::transfer_at_least(1),
                                        boost::bind(&Connection::handle_read_headers,
                                            //shared_from_this(),
                                            this,
                                            boost::asio::placeholders::error,
                                            boost::asio::placeholders::bytes_transferred));
        }
        else
        {
            RespReaded = len - idx - 4;
            idx = m_headers.find("\r\n");
            std::string respString = m_headers.substr(0, idx);
            RespLen = -1;
            parseHeaders(m_headers.substr(idx+2), respHeaders);
            std::string reqConnString = "", respConnString = "";
            std::string respVersion = respString.substr(respString.find("HTTP/")+5,3);
            headersMap::iterator it = respHeaders.find("Content-Length");
            if ( it != respHeaders.end() )
                RespLen = boost::lexical_cast<int>(it->second);
            it = respHeaders.find("Connection");
            if ( it != respHeaders.end() )
                respConnString = it->second;
            it = respHeaders.find("Connection");
            if ( it != respHeaders.end() )
                reqConnString = it->second;

            //isPersistent = (
            //  ((m_req_version == "1.1" && reqConnString != "close") ||
            //   (m_req_version == "1.0" && reqConnString == "keep-alive" )) &&
            //  ((respVersion == "1.1" && respConnString != "close") ||
            //   (respVersion == "1.0" && respConnString == "kepp-alive" )) &&
            //  RespLen != -1 );

            std::cout<<"Header Received :: "<<m_headers;

            boost::asio::async_read(socket_, boost::asio::buffer(sbuffer, len),
                boost::asio::transfer_at_least(1),
                boost::bind(&Connection::handle_server_read_body,
                                //shared_from_this(),
                                this,
                                boost::asio::placeholders::error,
                                boost::asio::placeholders::bytes_transferred));

            //boost::asio::async_write(bsocket_, boost::asio::buffer(m_headers),
            //  boost::bind(&Connection::handle_browser_write,
            //              shared_from_this(),
            //              boost::asio::placeholders::error,
            //              boost::asio::placeholders::bytes_transferred));
        }
    }
    else
    {
        shutdown();
    }

    std::cout<<__FUNCTION__<<"ENDS"<<std::endl;
} //handle_server_read_headers


void Connection::handle_server_read_body(const bs::error_code & err, size_t len) //called
{
    std::cout<<__FUNCTION__<<"BEGINS"<<std::endl;

    if ( !err || err == boost::asio::error::eof )
    {
        std::cout<<"Data received :: "<<std::string(sbuffer.begin(), sbuffer.end())<<std::endl;
        RespReaded += len;

        boost::asio::async_read(socket_, boost::asio::buffer(sbuffer, len),
        boost::asio::transfer_at_least(1),
        boost::bind(&Connection::handle_server_read_body,
                        //shared_from_this(),
                        this,
                        boost::asio::placeholders::error,
                        boost::asio::placeholders::bytes_transferred));
        //if ( err == boost::asio::error::eof )
        //  proxy_closed = true;
        //boost::asio::async_write(bsocket_, boost::asio::buffer(sbuffer, len),
        //  boost::bind(&Connection::handle_browser_write,
        //              shared_from_this(),
        //              boost::asio::placeholders::error,
        //              boost::asio::placeholders::bytes_transferred));
    }
    else
    {
        shutdown();
    }

    std::cout<<__FUNCTION__<<"ENDS"<<std::endl;
} //handle_server_read_body

void Connection::handle_read_headers(const bs::error_code & err, size_t len)
{
    if (!err)
    {
        std::cout<<"Bytes Received ... :: "<<len<<std::endl;
        if ( m_headers.empty())
        {
            m_headers = std::string(sbuffer.data(), len);
        }
        else
        {
            m_headers += std::string(sbuffer.data(), len);
        }
        if ( m_headers.find("\r\n\r\n") == std::string::npos )
        {
            boost::asio::async_read(socket_, ba::buffer(sbuffer), ba::transfer_at_least(1),
                boost::bind(&Connection::handle_read_headers, 
                            //shared_from_this(),
                            this,
                            ba::placeholders::error,
                            ba::placeholders::bytes_transferred));
        }
        else
        {
            std::string::size_type idx = m_headers.find("\r\n");
            std::string reqString = m_headers.substr(0, idx);
            m_headers.erase(0, idx+2);

            idx = reqString.find(" ");
            if ( idx == std::string::npos )
            {
                std::cout<<"Bad first line : "<<reqString<<std::endl;
                return;
            }

            m_method = reqString.substr(0, idx);
            reqString = reqString.substr(idx+1);
            idx = reqString.find(" ");
            if ( idx == std::string::npos )
            {
                std::cout<<"Bad first line of request : "<< reqString << std::endl;
                return;
            }

            m_url = reqString.substr(0,idx);
            m_req_version = reqString.substr(idx+1);
            idx = m_req_version.find("/");
            if ( idx == std::string::npos )
            {
                std::cout<<"Bad first line of request : "<<reqString<<std::endl;
                return;
            }

            m_req_version = m_req_version.substr(idx+1);
            parseHeaders(m_headers, reqHeaders);

            //start_connect();
        }
    }
    else
    {
        shutdown();
    }
}


void Connection::parseHeaders(const std::string & h, headersMap & hm)
{
    std::string str(h);
    std::string::size_type idx;
    std::string t;

    while ( (idx=str.find("\r\n")) != std::string::npos )
    {
        t = str.substr(0, idx);
        str.erase(0, idx+2);
        if ( t == "" )
            break;
        idx = t.find(": ");
        if ( idx == std::string::npos )
        {
            std::cout<<"Bad header line: "<<t<<std::endl;
            break;
        }

        hm.insert(std::make_pair(t.substr(0, idx), t.substr(idx+2)));
    }
} //parseHeaders


void Connection::shutdown()
{
    std::cout<<"Closing socket..."<<std::endl;
    socket_.close();
    //bsocket_.close();
} //shutdown

common.h

#ifndef COMMON_H
#define COMMON_H

#include <boost/asio.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>

#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>

#include <boost/regex.hpp>

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

#include <iostream>
#include <string>
#include <boost/utility.hpp>

namespace ba=boost::asio;
namespace bs=boost::system;

typedef boost::shared_ptr<ba::ip::tcp::socket> socket_ptr;
typedef boost::shared_ptr<ba::io_service> io_service_ptr;

#endif

リンカーエラーは

1>------ Rebuild All started: Project: yql_asio, Configuration: Debug Win32 ------
1>Build started 20-03-2013 AM 1:06:33.
1>InitializeBuildStatus:
1>  Touching "Debug\yql_asio.unsuccessfulbuild".
1>ClCompile:
1>  stdafx.cpp
1>  yql_conn.h
1>  Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:
1>  - add -D_WIN32_WINNT=0x0501 to the compiler command line; or
1>  - add _WIN32_WINNT=0x0501 to your project's Preprocessor Definitions.
1>  Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target).
1>  yql_conn.cpp
1>  Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:
1>  - add -D_WIN32_WINNT=0x0501 to the compiler command line; or
1>  - add _WIN32_WINNT=0x0501 to your project's Preprocessor Definitions.
1>  Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target).
1>  yql_asio.cpp
1>  Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:
1>  - add -D_WIN32_WINNT=0x0501 to the compiler command line; or
1>  - add _WIN32_WINNT=0x0501 to your project's Preprocessor Definitions.
1>  Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target).
1>  Yql.cpp
1>  Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:
1>  - add -D_WIN32_WINNT=0x0501 to the compiler command line; or
1>  - add _WIN32_WINNT=0x0501 to your project's Preprocessor Definitions.
1>  Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target).
1>  Generating Code...
1>Debug\yql_conn.obj : warning LNK4042: object specified more than once; extras ignored
1>Yql.obj : error LNK2019: unresolved external symbol "public: __thiscall Connection::Connection(class boost::asio::io_service &,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (??0Connection@@QAE@AAVio_service@asio@boost@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) referenced in function "public: __thiscall Yql::Yql(class boost::asio::io_service &,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (??0Yql@@QAE@AAVio_service@asio@boost@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z)
1>Yql.obj : error LNK2019: unresolved external symbol "public: void __thiscall Connection::start(void)" (?start@Connection@@QAEXXZ) referenced in function "public: void __thiscall Yql::GetResponse(void)" (?GetResponse@Yql@@QAEXXZ)
1>C:\Users\asit\Documents\Visual Studio 2010\Projects\yql_asio\Debug\yql_asio.exe : fatal error LNK1120: 2 unresolved externals
1>
1>Build FAILED.
1>
1>Time Elapsed 00:00:31.88
========== Rebuild All: 0 succeeded, 1 failed, 0 skipped ==========

バグを修正するのを手伝ってください。

4

1 に答える 1

1

LNK2019エラーが2つあります。最初のものは、2引数の接続コンストラクターが見つからないことを示しています。2つ目は、接続クラスからstartメソッドが見つからないことを示しています。LNK4042警告もあります。この警告は、yql_conn.hおよびyql_conn.cppで定義されているConnectionクラスへのリンクの問題に気づき、ファイルに明示的にリンクしようとしたことを示しています。明示的なリンクはおそらく正しいですが、2つのバージョンが浮かんでいるため、もう1つを取得し、明示的なリンクを無視しました。それはあなたがこの警告を受け取っている理由を説明するでしょう。

したがって、問題はバージョン管理の1つであるか、または取得している他の誰かによって作成された別のConnectionクラスがあると思われます。接続クラスを別の場所で定義した可能性があります。別のファイルまたは同じファイルで、別のフォルダーにあります。このファイルの古いバージョンには、おそらくConnectionコンストラクターが適切に定義されておらず、startメソッドの定義もありません。これは未解決のリンクエラーを説明します。したがって、実行しようとするのは、yql.hまたはyql.cppに移動し、[接続]を右クリックすることです。[定義に移動]を選択します。startの定義があるファイルに移動し、コンストラクターが正しく表示される場合は、もう一度[接続]を右クリックして、[すべての参照の検索]を選択してみてください。すべてのファイルでConnectionを検索することもできます。

于 2013-03-19T21:46:11.263 に答える