制作 Boost::Asio chat_server 示例的头文件给我 "one or multiple defined symbols found" 错误
Making a header file of the Boost::Asio chat_server example gives me "one or multiple defined symbols found" error
我是 c++ 和 boost 库的新手,试图通过从这个例子中制作三个单独的文件来学习头文件。 https://www.boost.org/doc/libs/1_70_0/doc/html/boost_asio/example/cpp11/chat/chat_server.cpp
chat_message.hpp 在这里,虽然我不认为这会导致问题。 https://www.boost.org/doc/libs/1_70_0/doc/html/boost_asio/example/cpp11/chat/chat_message.hpp
目标是将示例分成三个部分。
- main.cpp
- chat_server.h - 声明的头文件
- chat_server.cpp - 实施
这是我的实现,但出现了两个错误。
- 错误列表-
LNK1169 > One or more multiple defined symbols found > File-> main.exe
LNK2005 > $dummy_return@asio@boost@@YAXXZ) already defined in chat_server.obj > file-> main.obj
输出
Build started...
1>------ Build started: Project: main, Configuration: Debug Win32 ------
1>main.obj : error LNK2005: "void __cdecl boost::asio::dummy_return<void>(void)" (??$dummy_return@X@asio@boost@@YAXXZ) already defined in chat_server.obj
1>C:\Users\Offline User\source\repos\main\Debug\main.exe : fatal error LNK1169: one or more multiply defined symbols found
1>Done building project "main.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
示例代码在分成三个部分之前运行良好。
我不知道它是否与 typedef 或 virtual 有关,因为其他 类 和方法对我来说非常简单易懂(根据我在网上学到的)。请帮帮我,让我知道我在这里缺少什么?谢谢。
- main.cpp
#include "chat_server.h"
int main(int argc, char* argv[])
{
try
{
if (argc < 2)
{
std::cerr << "Usage: chat_server <port> [<port> ...]\n";
return 1;
}
boost::asio::io_context io_context;
std::list<chat_server> servers;
for (int i = 1; i < argc; ++i)
{
tcp::endpoint endpoint(tcp::v4(), std::atoi(argv[i]));
servers.emplace_back(io_context, endpoint);
}
io_context.run();
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
- chat_server.h
#ifndef CHAT_SERVER_H
#define CHAT_SERVER_H
#include <cstdlib>
#include <deque>
#include <iostream>
#include <list>
#include <memory>
#include <set>
#include <utility>
#include <boost/asio.hpp>
#include "chat_message.hpp"
using boost::asio::ip::tcp;
//----------------------------------------------------------------------
typedef std::deque<chat_message> chat_message_queue;
//----------------------------------------------------------------------
class chat_participant
{
public:
virtual ~chat_participant() {};
virtual void deliver(const chat_message& msg) = 0;
};
typedef std::shared_ptr<chat_participant> chat_participant_ptr;
//----------------------------------------------------------------------
class chat_room
{
public:
void join(chat_participant_ptr participant);
void leave(chat_participant_ptr participant);
void deliver(const chat_message& msg);
private:
std::set<chat_participant_ptr> participants_;
enum { max_recent_msgs = 100 };
chat_message_queue recent_msgs_;
};
//----------------------------------------------------------------------
class chat_session
: public chat_participant,
public std::enable_shared_from_this<chat_session>
{
public:
chat_session(tcp::socket socket, chat_room& room);
void start();
void deliver(const chat_message& msg);
private:
void do_read_header();
void do_read_body();
void do_write();
tcp::socket socket_;
chat_room& room_;
chat_message read_msg_;
chat_message_queue write_msgs_;
};
//----------------------------------------------------------------------
class chat_server
{
public:
chat_server(boost::asio::io_context& io_context,
const tcp::endpoint& endpoint);
private:
void do_accept();
tcp::acceptor acceptor_;
chat_room room_;
};
#endif
- chat_server.cpp
#include "chat_server.h"
void chat_room::join(chat_participant_ptr participant)
{
participants_.insert(participant);
for (auto msg : recent_msgs_)
participant->deliver(msg);
}
void chat_room::leave(chat_participant_ptr participant)
{
participants_.erase(participant);
}
void chat_room::deliver(const chat_message& msg)
{
recent_msgs_.push_back(msg);
while (recent_msgs_.size() > max_recent_msgs)
recent_msgs_.pop_front();
for (auto participant : participants_)
participant->deliver(msg);
}
//----------------------------------------------------------------------
chat_session::chat_session(tcp::socket socket, chat_room& room)
: socket_(std::move(socket)),
room_(room)
{
}
void chat_session::start()
{
room_.join(shared_from_this());
do_read_header();
}
void chat_session::deliver(const chat_message& msg)
{
bool write_in_progress = !write_msgs_.empty();
write_msgs_.push_back(msg);
if (!write_in_progress)
{
do_write();
}
}
void chat_session::do_read_header()
{
auto self(shared_from_this());
boost::asio::async_read(socket_,
boost::asio::buffer(read_msg_.data(), chat_message::header_length),
[this, self](boost::system::error_code ec, std::size_t /*length*/)
{
if (!ec && read_msg_.decode_header())
{
do_read_body();
}
else
{
room_.leave(shared_from_this());
}
});
}
void chat_session::do_read_body()
{
auto self(shared_from_this());
boost::asio::async_read(socket_,
boost::asio::buffer(read_msg_.body(), read_msg_.body_length()),
[this, self](boost::system::error_code ec, std::size_t /*length*/)
{
if (!ec)
{
room_.deliver(read_msg_);
do_read_header();
}
else
{
room_.leave(shared_from_this());
}
});
}
void chat_session::do_write()
{
auto self(shared_from_this());
boost::asio::async_write(socket_,
boost::asio::buffer(write_msgs_.front().data(),
write_msgs_.front().length()),
[this, self](boost::system::error_code ec, std::size_t /*length*/)
{
if (!ec)
{
write_msgs_.pop_front();
if (!write_msgs_.empty())
{
do_write();
}
}
else
{
room_.leave(shared_from_this());
}
});
}
//----------------------------------------------------------------------
chat_server::chat_server(boost::asio::io_context& io_context,
const tcp::endpoint& endpoint)
: acceptor_(io_context, endpoint)
{
do_accept();
}
void chat_server::do_accept()
{
acceptor_.async_accept(
[this](boost::system::error_code ec, tcp::socket socket)
{
if (!ec)
{
std::make_shared<chat_session>(std::move(socket), room_)->start();
}
do_accept();
});
}
见https://github.com/chriskohlhoff/asio/pull/584
include/boost/asio/impl/use_awaitable.hpp
有错误,dummy_return
应该标记为inline
。
变化:
template <>
void dummy_return()
{
}
至:
template <>
inline void dummy_return()
{
}
我是 c++ 和 boost 库的新手,试图通过从这个例子中制作三个单独的文件来学习头文件。 https://www.boost.org/doc/libs/1_70_0/doc/html/boost_asio/example/cpp11/chat/chat_server.cpp chat_message.hpp 在这里,虽然我不认为这会导致问题。 https://www.boost.org/doc/libs/1_70_0/doc/html/boost_asio/example/cpp11/chat/chat_message.hpp
目标是将示例分成三个部分。
- main.cpp
- chat_server.h - 声明的头文件
- chat_server.cpp - 实施
这是我的实现,但出现了两个错误。
- 错误列表-
LNK1169 > One or more multiple defined symbols found > File-> main.exe
LNK2005 > $dummy_return@asio@boost@@YAXXZ) already defined in chat_server.obj > file-> main.obj
输出
Build started...
1>------ Build started: Project: main, Configuration: Debug Win32 ------
1>main.obj : error LNK2005: "void __cdecl boost::asio::dummy_return<void>(void)" (??$dummy_return@X@asio@boost@@YAXXZ) already defined in chat_server.obj
1>C:\Users\Offline User\source\repos\main\Debug\main.exe : fatal error LNK1169: one or more multiply defined symbols found
1>Done building project "main.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
示例代码在分成三个部分之前运行良好。 我不知道它是否与 typedef 或 virtual 有关,因为其他 类 和方法对我来说非常简单易懂(根据我在网上学到的)。请帮帮我,让我知道我在这里缺少什么?谢谢。
- main.cpp
#include "chat_server.h"
int main(int argc, char* argv[])
{
try
{
if (argc < 2)
{
std::cerr << "Usage: chat_server <port> [<port> ...]\n";
return 1;
}
boost::asio::io_context io_context;
std::list<chat_server> servers;
for (int i = 1; i < argc; ++i)
{
tcp::endpoint endpoint(tcp::v4(), std::atoi(argv[i]));
servers.emplace_back(io_context, endpoint);
}
io_context.run();
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
- chat_server.h
#ifndef CHAT_SERVER_H
#define CHAT_SERVER_H
#include <cstdlib>
#include <deque>
#include <iostream>
#include <list>
#include <memory>
#include <set>
#include <utility>
#include <boost/asio.hpp>
#include "chat_message.hpp"
using boost::asio::ip::tcp;
//----------------------------------------------------------------------
typedef std::deque<chat_message> chat_message_queue;
//----------------------------------------------------------------------
class chat_participant
{
public:
virtual ~chat_participant() {};
virtual void deliver(const chat_message& msg) = 0;
};
typedef std::shared_ptr<chat_participant> chat_participant_ptr;
//----------------------------------------------------------------------
class chat_room
{
public:
void join(chat_participant_ptr participant);
void leave(chat_participant_ptr participant);
void deliver(const chat_message& msg);
private:
std::set<chat_participant_ptr> participants_;
enum { max_recent_msgs = 100 };
chat_message_queue recent_msgs_;
};
//----------------------------------------------------------------------
class chat_session
: public chat_participant,
public std::enable_shared_from_this<chat_session>
{
public:
chat_session(tcp::socket socket, chat_room& room);
void start();
void deliver(const chat_message& msg);
private:
void do_read_header();
void do_read_body();
void do_write();
tcp::socket socket_;
chat_room& room_;
chat_message read_msg_;
chat_message_queue write_msgs_;
};
//----------------------------------------------------------------------
class chat_server
{
public:
chat_server(boost::asio::io_context& io_context,
const tcp::endpoint& endpoint);
private:
void do_accept();
tcp::acceptor acceptor_;
chat_room room_;
};
#endif
- chat_server.cpp
#include "chat_server.h"
void chat_room::join(chat_participant_ptr participant)
{
participants_.insert(participant);
for (auto msg : recent_msgs_)
participant->deliver(msg);
}
void chat_room::leave(chat_participant_ptr participant)
{
participants_.erase(participant);
}
void chat_room::deliver(const chat_message& msg)
{
recent_msgs_.push_back(msg);
while (recent_msgs_.size() > max_recent_msgs)
recent_msgs_.pop_front();
for (auto participant : participants_)
participant->deliver(msg);
}
//----------------------------------------------------------------------
chat_session::chat_session(tcp::socket socket, chat_room& room)
: socket_(std::move(socket)),
room_(room)
{
}
void chat_session::start()
{
room_.join(shared_from_this());
do_read_header();
}
void chat_session::deliver(const chat_message& msg)
{
bool write_in_progress = !write_msgs_.empty();
write_msgs_.push_back(msg);
if (!write_in_progress)
{
do_write();
}
}
void chat_session::do_read_header()
{
auto self(shared_from_this());
boost::asio::async_read(socket_,
boost::asio::buffer(read_msg_.data(), chat_message::header_length),
[this, self](boost::system::error_code ec, std::size_t /*length*/)
{
if (!ec && read_msg_.decode_header())
{
do_read_body();
}
else
{
room_.leave(shared_from_this());
}
});
}
void chat_session::do_read_body()
{
auto self(shared_from_this());
boost::asio::async_read(socket_,
boost::asio::buffer(read_msg_.body(), read_msg_.body_length()),
[this, self](boost::system::error_code ec, std::size_t /*length*/)
{
if (!ec)
{
room_.deliver(read_msg_);
do_read_header();
}
else
{
room_.leave(shared_from_this());
}
});
}
void chat_session::do_write()
{
auto self(shared_from_this());
boost::asio::async_write(socket_,
boost::asio::buffer(write_msgs_.front().data(),
write_msgs_.front().length()),
[this, self](boost::system::error_code ec, std::size_t /*length*/)
{
if (!ec)
{
write_msgs_.pop_front();
if (!write_msgs_.empty())
{
do_write();
}
}
else
{
room_.leave(shared_from_this());
}
});
}
//----------------------------------------------------------------------
chat_server::chat_server(boost::asio::io_context& io_context,
const tcp::endpoint& endpoint)
: acceptor_(io_context, endpoint)
{
do_accept();
}
void chat_server::do_accept()
{
acceptor_.async_accept(
[this](boost::system::error_code ec, tcp::socket socket)
{
if (!ec)
{
std::make_shared<chat_session>(std::move(socket), room_)->start();
}
do_accept();
});
}
见https://github.com/chriskohlhoff/asio/pull/584
include/boost/asio/impl/use_awaitable.hpp
有错误,dummy_return
应该标记为inline
。
变化:
template <>
void dummy_return()
{
}
至:
template <>
inline void dummy_return()
{
}