
Boost.Asio server application close get "This application has requested the Runtime to terminate it in an unusual way." My code is too mush! std.hpp: /* ** author: ylj ** create: 2009/08/27 */ #ifndef STD_HPP #define STD_HPP #include <algorithm> #include <bitset> #include <complex> #include <deque> #include <exception> #include <fstream> #include <functional> #include <iomanip> #include <ios> #include <iosfwd> #include <iostream> #include <istream> #include <iterator> #include <limits> #include <list> #include <locale> #include <map> #include <memory> #include <new> #include <numeric> #include <ostream> #include <queue> #include <set> #include <sstream> #include <stack> #include <stdexcept> #include <streambuf> #include <string> #include <strstream> #include <utility> #include <vector> #include <cassert> #include <cctype> #include <cerrno> #include <cfloat> #include <climits> #include <clocale> #include <cmath> #include <csetjmp> #include <csignal> #include <cstdarg> #include <cstddef> #include <cstdio> #include <cstdlib> #include <cstring> #include <ctime> #include <cwchar> #include <cwctype> #endif // STD_HPP tcontainer.hpp: /* ** author: ylj ** create: 2010/02/10 */ #ifndef TCONTAINER_HPP #define TCONTAINER_HPP #include <deque> #include <list> #include <map> #include <queue> #include <set> #include <stack> #include <vector> #if 0 #include <boost/pool/pool_alloc.hpp> template<typename T> class tvector : public std::vector<T, boost::pool_allocator<T> > { }; template<typename T> class tdeque: public std::deque<T, boost::pool_allocator<T> > { }; template<typename T> class tlist: public std::list<T, boost::fast_pool_allocator<T> > { }; template<typename T> class tstack: public std::stack<T, tdeque<T> > { }; template<typename T> class tqueue: public std::queue<T, tdeque<T> > { }; template<typename T> class tpriority_queue: public std::priority_queue<T, tdeque<T> > /* NOTE: use tvector will crash if compiled by gcc, why? */ { }; template<typename T> class tset: public std::set<T, std::less<T>, boost::pool_allocator<T> > { }; template<typename T> class tmultiset: public std::multiset<T, std::less<T>, boost::pool_allocator<T> > { }; template<typename K, typename V> class tmap: public std::map<K, V, std::less<K>, boost::pool_allocator<std::pair<K, V> > > { }; template<typename K, typename V> class tmultimap: public std::multimap<K, V, std::less<K>, boost::pool_allocator<std::pair<K, V> > > { }; #else template<typename T> class tvector : public std::vector<T> { }; template<typename T> class tdeque: public std::deque<T> { }; template<typename T> class tlist: public std::list<T> { }; template<typename T> class tstack: public std::stack<T, tdeque<T> > { }; template<typename T> class tqueue: public std::queue<T, tdeque<T> > { }; template<typename T> class tpriority_queue: public std::priority_queue<T> { }; template<typename T> class tset: public std::set<T> { }; template<typename T> class tmultiset: public std::multiset<T> { }; template<typename K, typename V> class tmap: public std::map<K, V> { }; template<typename K, typename V> class tmultimap: public std::multimap<K, V> { }; #endif #endif // TCONTAINER_HPP tstring.hpp: /* ** author: ylj ** create: 2010/02/20 */ #ifndef TSTRING_HPP #define TSTRING_HPP #include <string> #include <sstream> #include <boost/pool/pool_alloc.hpp> typedef std::basic_string<char, std::char_traits<char>, boost::pool_allocator<char> > tstring; typedef std::basic_string<wchar_t, std::char_traits<wchar_t>, boost::pool_allocator<wchar_t> > twstring; typedef std::basic_stringstream<char, std::char_traits<char>, boost::pool_allocator<char> > tstringstream; typedef std::basic_stringstream<wchar_t, std::char_traits<wchar_t>, boost::pool_allocator<wchar_t> > twstringstream; typedef std::basic_istringstream<char, std::char_traits<char>, boost::pool_allocator<char> > tistringstream; typedef std::basic_istringstream<wchar_t, std::char_traits<wchar_t>, boost::pool_allocator<wchar_t> > twistringstream; typedef std::basic_ostringstream<char, std::char_traits<char>, boost::pool_allocator<char> > tostringstream; typedef std::basic_ostringstream<wchar_t, std::char_traits<wchar_t>, boost::pool_allocator<wchar_t> > twostringstream; typedef std::basic_stringbuf<char, std::char_traits<char>, boost::pool_allocator<char> > tstringbuf; typedef std::basic_stringbuf<wchar_t, std::char_traits<wchar_t>, boost::pool_allocator<wchar_t> > twstringbuf; #endif // TSTRING_HPP tcp_packet.h: /* ** author: ylj ** create: 2010/03/01 */ #ifndef TCP_PACKET_H_ #define TCP_PACKET_H_ #define TCP_PACKET_HEARTBEAT_COMMAND -1 #include "std.hpp" class tcp_packet { public: typedef struct header { unsigned short length; int command; } header; enum { header_length = sizeof(header), max_body_length = 1024 * 4 }; public: tcp_packet() : body_length_(0), command_(0) {} inline const char * data() const { return data_; } inline char * data() { return data_; } inline size_t length() const { return header_length + body_length_; } inline int command() const { return command_; } inline void command(int cmd) { command_ = cmd; } inline const char * body() const { return data_ + header_length; } inline char * body() { return data_ + header_length; } inline size_t body_length() const{ return body_length_; } inline void body_length(size_t length) { body_length_ = length; if (body_length_ > max_body_length) body_length_ = max_body_length; } inline bool decode_header() { using namespace std; header hd; memcpy(&hd, data_, header_length); body_length_ = hd.length; command_ = hd.command; if (body_length_ > max_body_length) { body_length_ = 0; command_ = 0; return false; } return true; } inline void encode_header() { using namespace std; header hd; hd.length = body_length_; hd.command = command_; memcpy(data_, &hd, header_length); } private: char data_[header_length + max_body_length]; size_t body_length_; int command_; }; #endif // TCP_PACKET_H_ net_command.h: /* ** author: ylj ** create: 2010/03/05 */ #ifndef NET_COMMAND_H_ #define NET_COMMAND_H_ #define NET_CMD_GAME_CLIENT_TO_GAME_SERVER_START 1000 #define NET_CMD_GAME_SERVER_TO_GAME_CLIENT_START 2000 #define NET_CMD_LOBBY_CLIENT_TO_LOBBY_SERVER_START 3000 #define NET_CMD_LOBBY_SERVER_TO_LOBBY_CLIENT_START 4000 #endif // NET_COMMAND_H_ net_command_game_client_to_game_server.h: /* ** author: ylj ** create: 2010/03/01 */ #ifndef NET_COMMAND_GAME_CLIENT_TO_GAME_SERVER_H_ #define NET_COMMAND_GAME_CLIENT_TO_GAME_SERVER_H_ #include "net_command.h" enum NET_CMD_GC_TO_GS { NET_CMD_GC_TO_GS_START = NET_CMD_GAME_CLIENT_TO_GAME_SERVER_START, NET_CMD_GC_TO_GS_TEST }; typedef struct CMD_GC_TO_GS_TEST { unsigned short x; unsigned short y; } CMD_GC_TO_GS_TEST; #endif // NET_COMMAND_GAME_CLIENT_TO_GAME_SERVER_H_ net_command_game_server_to_game_client.h: /* ** author: ylj ** create: 2010/03/01 */ #ifndef NET_COMMAND_GAME_SERVER_TO_GAME_CLIENT_H_ #define NET_COMMAND_GAME_SERVER_TO_GAME_CLIENT_H_ #include "net_command.h" enum NET_CMD_GS_TO_GC { NET_CMD_GS_TO_GC_START = NET_CMD_GAME_SERVER_TO_GAME_CLIENT_START, NET_CMD_GS_TO_GC_TEST, }; typedef struct CMD_GS_TO_GC_TEST { unsigned int id; unsigned short x; unsigned short y; } CMD_GS_TO_GC_TEST; #endif // NET_COMMAND_GAME_SERVER_TO_GAME_CLIENT_H_ tcp_server.h: /* ** author: ylj ** create: 2010/02/26 */ #ifndef TCP_SERVER_H_ #define TCP_SERVER_H_ #include "tcp_session.h" #include "tcontainer.hpp" #include <boost/asio.hpp> class tcp_server_club; class tcp_server { public: tcp_server(boost::asio::io_service &io_service, const boost::asio::ip::tcp::endpoint &endpoint, tcp_server_club &club, int max_session_count); virtual ~tcp_server(); tcp_session * take_session(); void release_session(int session_id); void accept(); int active_count() const; void close(); private: void handle_accept(tcp_session *session, const boost::system::error_code &error); void do_accept(); void do_close(); private: typedef tdeque<tcp_session *> tcp_session_container; typedef tmap<int, tcp_session *> tcp_session_map; tcp_session_container idle_sessions_; tcp_session_map active_sessions_; boost::asio::io_service &io_service_; boost::asio::ip::tcp::acceptor acceptor_; tcp_server_club &club_; int max_session_count_; }; #endif // TCP_SERVER_H_ tcp_server.cpp: /* ** author: ylj ** create: 2010/02/26 */ #include "tcp_server.h" #include "tcp_session.h" #include "tcp_server_club.h" #include <boost/bind.hpp> tcp_server::tcp_server(boost::asio::io_service &io_service, const boost::asio::ip::tcp::endpoint &endpoint, tcp_server_club &club, int max_session_count) : io_service_(io_service), acceptor_(io_service, endpoint), club_(club) { max_session_count_ = max_session_count; for (int i = 0; i < max_session_count; ++i) { tcp_session *session(new tcp_session(io_service_, club_, this, i)); idle_sessions_.push_back(session); } } tcp_server::~tcp_server() { tcp_session_container::iterator it = idle_sessions_.begin(); for ( ; it != idle_sessions_.end(); ++it) delete *it; tcp_session_map::iterator ufo = active_sessions_.begin(); for ( ; ufo != active_sessions_.end(); ++ufo) delete ufo->second; assert(max_session_count_ == (int)idle_sessions_.size() + (int)active_sessions_.size()); } tcp_session * tcp_server::take_session() { std::cout << "tcp_server::take_session" << std::endl; if (idle_sessions_.empty()) return NULL; tcp_session *ret = idle_sessions_.front(); idle_sessions_.pop_front(); active_sessions_.insert(std::make_pair(ret->id(), ret)); return ret; } void tcp_server::release_session(int session_id) { std::cout << "tcp_server::release_session" << std::endl; tcp_session_map::iterator it = active_sessions_.find(session_id); if (it == active_sessions_.end()) return; tcp_session *session = it->second; club_.leave(session); session->socket().close(); idle_sessions_.push_front(session); active_sessions_.erase(it); /* can accept again */ if (idle_sessions_.size() == 1 && acceptor_.is_open()) { do_accept(); } } void tcp_server::accept() { std::cout << "tcp_server::accept" << std::endl; io_service_.post(boost::bind(&tcp_server::do_accept, this)); } int tcp_server::active_count() const { return static_cast<int>(active_sessions_.size()); } void tcp_server::close() { std::cout << "tcp_server::close" << std::endl; io_service_.post(boost::bind(&tcp_server::do_close, this)); } void tcp_server::handle_accept(tcp_session *session, const boost::system::error_code &error) { std::cout << "tcp_server::handle_accept" << std::endl; if (!error) { club_.join(session); session->start(); do_accept(); } else { std::cout << "tcp_server::handle_accept error" << std::endl; session->socket().close(); } } void tcp_server::do_accept() { std::cout << "tcp_server::do_accept" << std::endl; tcp_session *new_session = take_session(); if (new_session) acceptor_.async_accept(new_session->socket(), boost::bind(&tcp_server::handle_accept, this, new_session, boost::asio::placeholders::error)); } void tcp_server::do_close() { std::cout << "tcp_server::do_close" << std::endl; acceptor_.close(); tcp_session_map all_active = active_sessions_; tcp_session_map::iterator it = all_active.begin(); for ( ; it != all_active.end(); ++it) { tcp_session *session = it->second; session->socket().close(); } } tcp_session.h: /* ** author: ylj ** create: 2010/02/26 */ #ifndef TCP_SESSION_H_ #define TCP_SESSION_H_ #include "tcp_packet.h" #include "tcp_server_member.h" #include "tcontainer.hpp" #include <boost/asio.hpp> class tcp_server; class tcp_server_club; class tcp_session : public tcp_server_member { public: tcp_session(boost::asio::io_service &io_service, tcp_server_club &club, tcp_server *parent, int id); ~tcp_session(); boost::asio::ip::tcp::socket & socket(); void start(); void send(const tcp_packet &pkt); virtual int id() const; virtual tstring address() const; virtual unsigned short port() const; virtual void send(int command, void *data, int size); virtual void close(); private: void handle_read_header(const boost::system::error_code &error); void handle_read_body(const boost::system::error_code &error); void handle_write(const boost::system::error_code &error); private: typedef tdeque<tcp_packet> tcp_packet_queue; boost::asio::ip::tcp::socket socket_; tcp_server_club &club_; tcp_packet read_packet_; tcp_packet_queue write_packets_; tcp_server *parent_; int id_; }; #endif // TCP_SESSION_H_ tcp_session.cpp: /* ** author: ylj ** create: 2010/03/01 */ #include "tcp_session.h" #include "tcp_server.h" #include "tcp_server_club.h" #include <boost/bind.hpp> tcp_session::tcp_session(boost::asio::io_service &io_service, tcp_server_club &club, tcp_server *parent, int id) : socket_(io_service), club_(club), parent_(parent), id_(id) { } tcp_session::~tcp_session() { } boost::asio::ip::tcp::socket & tcp_session::socket() { return socket_; } void tcp_session::start() { boost::asio::async_read(socket_, boost::asio::buffer(read_packet_.data(), tcp_packet::header_length), boost::bind(&tcp_session::handle_read_header, this, boost::asio::placeholders::error)); } void tcp_session::send(const tcp_packet &pkt) { bool write_in_progress = !write_packets_.empty(); write_packets_.push_back(pkt); if (!write_in_progress) { boost::asio::async_write(socket_, boost::asio::buffer(write_packets_.front().data(), write_packets_.front().length()), boost::bind(&tcp_session::handle_write, this, boost::asio::placeholders::error)); } } int tcp_session::id() const { return id_; } tstring tcp_session::address() const { return socket_.remote_endpoint().address().to_string().c_str(); } unsigned short tcp_session::port() const { return socket_.remote_endpoint().port(); } void tcp_session::send(int command, void *data, int size) { assert(tcp_packet::max_body_length >= size); tcp_packet pkt; pkt.command(command); pkt.body_length(size); memcpy(pkt.body(), data, pkt.body_length()); pkt.encode_header(); this->send(pkt); } void tcp_session::close() { socket_.close(); } void tcp_session::handle_read_header(const boost::system::error_code &error) { if (!error && read_packet_.decode_header()) { boost::asio::async_read(socket_, boost::asio::buffer(read_packet_.body(), read_packet_.body_length()), boost::bind(&tcp_session::handle_read_body, this, boost::asio::placeholders::error)); } else { parent_->release_session(id_); } } void tcp_session::handle_read_body(const boost::system::error_code &error) { if (!error) { if (read_packet_.command() != TCP_PACKET_HEARTBEAT_COMMAND) club_.receive(this, read_packet_.command(), read_packet_.body(), read_packet_.body_length()); boost::asio::async_read(socket_, boost::asio::buffer(read_packet_.data(), tcp_packet::header_length), boost::bind(&tcp_session::handle_read_header, this, boost::asio::placeholders::error)); } else { parent_->release_session(id_); } } void tcp_session::handle_write(const boost::system::error_code &error) { if (!error) { write_packets_.pop_front(); if (!write_packets_.empty()) { boost::asio::async_write(socket_, boost::asio::buffer(write_packets_.front().data(), write_packets_.front().length()), boost::bind(&tcp_session::handle_write, this, boost::asio::placeholders::error)); } } else { parent_->release_session(id_); } } tcp_server_member.h: /* ** author: ylj ** create: 2010/03/01 */ #ifndef TCP_SERVER_MEMBER_H_ #define TCP_SERVER_MEMBER_H_ #include "tstring.hpp" class tcp_server_member { public: virtual ~tcp_server_member() {} virtual int id() const = 0; virtual tstring address() const = 0; virtual unsigned short port() const = 0; virtual void send(int command, void *data, int size) = 0; virtual void close() = 0; }; #endif // TCP_SERVER_MEMBER_H_ tcp_server_club.h: /* ** author: ylj ** create: 2010/03/01 */ #ifndef TCP_SERVER_CLUB_H_ #define TCP_SERVER_CLUB_H_ #include "tcontainer.hpp" #include <boost/function.hpp> class tcp_server_member; class tcp_server_club { public: virtual ~tcp_server_club(); void receive(tcp_server_member *member, int command, void *data, int size); template <typename ReceiveHandler> void bind_receive_handler(int command, ReceiveHandler handler); virtual void join(tcp_server_member *member); virtual void leave(tcp_server_member *member); private: typedef boost::function<void (tcp_server_member *, void *, int)> receive_handler; typedef tmap<int, receive_handler> receive_handler_map; receive_handler_map receive_handlers_; }; template <typename ReceiveHandler> void tcp_server_club::bind_receive_handler(int command, ReceiveHandler handler) { receive_handlers_.insert(std::make_pair(command, handler)); } #endif // TCP_SERVER_CLUB_H_ tcp_server_club.cpp: /* ** author: ylj ** create: 2010/03/01 */ #include "tcp_server_club.h" #include "tcp_server_member.h" #include "std.hpp" tcp_server_club::~tcp_server_club() { } void tcp_server_club::receive(tcp_server_member *member, int command, void *data, int size) { receive_handler_map::iterator it = receive_handlers_.find(command); if (it != receive_handlers_.end()) { receive_handler handler = it->second; handler(member, data, size); } else { std::cout << "unhandle session(" << member->id() << ")'s command: " << command << std::endl; } } void tcp_server_club::join(tcp_server_member *member) { } void tcp_server_club::leave(tcp_server_member *member) { } game_server_club.h: /* ** author: ylj ** create: 2010/03/01 */ #ifndef GAME_SERVER_CLUB_H_ #define GAME_SERVER_CLUB_H_ #include "tcp_server_club.h" class game_server_club : public tcp_server_club { public: game_server_club(); virtual void join(tcp_server_member *member); virtual void leave(tcp_server_member *member); void ON_NET_CMD_GC_TO_GS_TEST(tcp_server_member *member, void *data, int size); }; #endif // GAME_SERVER_CLUB_H_ game_server_club.cpp: /* ** author: ylj ** create: 2010/03/01 */ #include "game_server_club.h" #include "tcp_server_member.h" #include "net_command_game_server_to_game_client.h" #include "net_command_game_client_to_game_server.h" #include "std.hpp" #include <boost/bind.hpp> game_server_club::game_server_club() { bind_receive_handler(NET_CMD_GC_TO_GS_TEST, boost::bind(&game_server_club::ON_NET_CMD_GC_TO_GS_TEST, this, _1, _2, _3)); } void game_server_club::join(tcp_server_member *member) { std::cout << "id:" << member->id() << " join(" << member->address() << ":" << member->port() << ")" << std::endl; } void game_server_club::leave(tcp_server_member *member) { std::cout << "id:" << member->id() << " leave(" << member->address() << ":" << member->port() << ")" << std::endl; } void game_server_club::ON_NET_CMD_GC_TO_GS_TEST(tcp_server_member *member, void *data, int size) { CMD_GC_TO_GS_TEST *rdata = (CMD_GC_TO_GS_TEST *)data; CMD_GS_TO_GC_TEST sdata; sdata.x = rdata->x; sdata.y = rdata->y; sdata.id= member->id(); std::cout << "id:" << sdata.id << " ON_NET_CMD_GC_TO_GS_TEST " << rdata->x << " " << rdata->y << std::endl; member->send(NET_CMD_GS_TO_GC_TEST, &sdata, sizeof(sdata)); //member->close(); } main.cpp: /* ** author: ylj ** create: 2010/03/01 */ #include "std.hpp" #include "tcp_server.h" #include "game_server_club.h" #include "tstring.hpp" #include <boost/thread.hpp> using namespace std; #ifdef _MSC_VER #include <dbghelp.h> #include <stdio.h> #include <crtdbg.h> #include <tchar.h> #include <windows.h> #pragma comment ( lib, "dbghelp.lib" ) /////////////////////////////////////////////////////////////////////////////// // Minidump creation function // void CreateMiniDump( EXCEPTION_POINTERS* pep ) { // Open the file HANDLE hFile = CreateFile( _T("MaxiDump.dmp"), GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if( ( hFile != NULL ) && ( hFile != INVALID_HANDLE_VALUE ) ) { // Create the minidump MINIDUMP_EXCEPTION_INFORMATION mdei; mdei.ThreadId = GetCurrentThreadId(); mdei.ExceptionPointers = pep; mdei.ClientPointers = FALSE; MINIDUMP_TYPE mdt = (MINIDUMP_TYPE)(MiniDumpWithFullMemory | MiniDumpWithFullMemoryInfo | MiniDumpWithHandleData | MiniDumpWithThreadInfo | MiniDumpWithUnloadedModules ); BOOL rv = MiniDumpWriteDump( GetCurrentProcess(), GetCurrentProcessId(), hFile, mdt, (pep != 0) ? &mdei : 0, 0, 0 ); if( !rv ) _tprintf( _T("MiniDumpWriteDump failed. Error: %u \n"), GetLastError() ); else _tprintf( _T("Minidump created.\n") ); // Close the file CloseHandle( hFile ); } else { _tprintf( _T("CreateFile failed. Error: %u \n"), GetLastError() ); } } #endif // _MSC_VER void do_work(int argc, const char *argv[]) { if (argc != 2) { std::cerr << "Usage: " << argv[0] << " <port>\n"; return; } boost::asio::io_service io_service; boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), atoi(argv[1])); game_server_club game_club; tcp_server game_server(io_service, endpoint, game_club, 2); game_server.accept(); boost::thread io_thread(boost::bind(&boost::asio::io_service::run, &io_service)); tstring line; cout << "? for help" << endl; while(getline(cin, line)) { if (line == "exit") { game_server.close(); break; } else if (line == "?") { cout << "exit ->close server" << endl; cout << "? ->help" << endl; } } io_thread.join(); } int main(int argc, const char *argv[]) { #ifdef _MSC_VER __try { #endif // _MSC_VER do_work(argc, argv); #ifdef _MSC_VER } __except( CreateMiniDump( GetExceptionInformation() ), EXCEPTION_EXECUTE_HANDLER ) { } #endif // _MSC_VER return 0; } If anyone conneted server and not close, I type "exit" to close server then got "This application has requested the Runtime to terminate it in an unusual way." I have check and check and check. I cannot find out why. Anyone can help me? Thank you first.