Boost.Asio server application close get "This application has requested the Runtime to terminate it in an unusual way."

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.

AMDG l.jay Yuan wrote:
Boost.Asio server application close get "This application has requested the Runtime to terminate it in an unusual way."
My code is too mush!
<snip>
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?
Can you run it under a debugger to find where it's crashing. In Christ, Steven Watanabe

in msvcrt.dll 2010/3/7 Steven Watanabe <watanabesj@gmail.com>:
AMDG
l.jay Yuan wrote:
Boost.Asio server application close get "This application has requested the Runtime to terminate it in an unusual way."
My code is too mush!
<snip>
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?
Can you run it under a debugger to find where it's crashing.
In Christ, Steven Watanabe
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

On Sun, Mar 7, 2010 at 5:58 PM, l.jay Yuan <pass86@gmail.com> wrote:
in msvcrt.dll
But in the callstack at that point, what is your last code that is called, better to just past the callstack here, or even better, post a complete compilable example that demonstrates your problem. Also, please do not top-post.

There is a sample base on Boost.Asio example --> chat. Most changes on chat_server.cpp chat_message.hpp: // // chat_message.hpp // ~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef CHAT_MESSAGE_HPP #define CHAT_MESSAGE_HPP #include <cstdio> #include <cstdlib> #include <cstring> class chat_message { public: enum { header_length = 4 }; enum { max_body_length = 512 }; chat_message() : body_length_(0) { } const char* data() const { return data_; } char* data() { return data_; } size_t length() const { return header_length + body_length_; } const char* body() const { return data_ + header_length; } char* body() { return data_ + header_length; } size_t body_length() const { return body_length_; } void body_length(size_t length) { body_length_ = length; if (body_length_ > max_body_length) body_length_ = max_body_length; } bool decode_header() { using namespace std; // For strncat and atoi. char header[header_length + 1] = ""; strncat(header, data_, header_length); body_length_ = atoi(header); if (body_length_ > max_body_length) { body_length_ = 0; return false; } return true; } void encode_header() { using namespace std; // For sprintf and memcpy. char header[header_length + 1] = ""; sprintf(header, "%4d", body_length_); memcpy(data_, header, header_length); } private: char data_[header_length + max_body_length]; size_t body_length_; }; #endif // CHAT_MESSAGE_HPP chat_client.cpp: // // chat_client.cpp // ~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #include <cstdlib> #include <deque> #include <iostream> #include <boost/bind.hpp> #include <boost/asio.hpp> #include <boost/thread.hpp> #include "chat_message.hpp" using boost::asio::ip::tcp; typedef std::deque<chat_message> chat_message_queue; class chat_client { public: chat_client(boost::asio::io_service& io_service, tcp::resolver::iterator endpoint_iterator) : io_service_(io_service), socket_(io_service) { tcp::endpoint endpoint = *endpoint_iterator; socket_.async_connect(endpoint, boost::bind(&chat_client::handle_connect, this, boost::asio::placeholders::error, ++endpoint_iterator)); } void write(const chat_message& msg) { io_service_.post(boost::bind(&chat_client::do_write, this, msg)); } void close() { io_service_.post(boost::bind(&chat_client::do_close, this)); } private: void handle_connect(const boost::system::error_code& error, tcp::resolver::iterator endpoint_iterator) { if (!error) { boost::asio::async_read(socket_, boost::asio::buffer(read_msg_.data(), chat_message::header_length), boost::bind(&chat_client::handle_read_header, this, boost::asio::placeholders::error)); } else if (endpoint_iterator != tcp::resolver::iterator()) { socket_.close(); tcp::endpoint endpoint = *endpoint_iterator; socket_.async_connect(endpoint, boost::bind(&chat_client::handle_connect, this, boost::asio::placeholders::error, ++endpoint_iterator)); } } void handle_read_header(const boost::system::error_code& error) { if (!error && read_msg_.decode_header()) { boost::asio::async_read(socket_, boost::asio::buffer(read_msg_.body(), read_msg_.body_length()), boost::bind(&chat_client::handle_read_body, this, boost::asio::placeholders::error)); } else { do_close(); } } void handle_read_body(const boost::system::error_code& error) { if (!error) { std::cout.write(read_msg_.body(), read_msg_.body_length()); std::cout << "\n"; boost::asio::async_read(socket_, boost::asio::buffer(read_msg_.data(), chat_message::header_length), boost::bind(&chat_client::handle_read_header, this, boost::asio::placeholders::error)); } else { do_close(); } } void do_write(chat_message msg) { bool write_in_progress = !write_msgs_.empty(); write_msgs_.push_back(msg); if (!write_in_progress) { boost::asio::async_write(socket_, boost::asio::buffer(write_msgs_.front().data(), write_msgs_.front().length()), boost::bind(&chat_client::handle_write, this, boost::asio::placeholders::error)); } } void handle_write(const boost::system::error_code& error) { if (!error) { write_msgs_.pop_front(); if (!write_msgs_.empty()) { boost::asio::async_write(socket_, boost::asio::buffer(write_msgs_.front().data(), write_msgs_.front().length()), boost::bind(&chat_client::handle_write, this, boost::asio::placeholders::error)); } } else { do_close(); } } void do_close() { socket_.close(); } private: boost::asio::io_service& io_service_; tcp::socket socket_; chat_message read_msg_; chat_message_queue write_msgs_; }; int main(int argc, char* argv[]) { try { if (argc != 3) { std::cerr << "Usage: chat_client <host> <port>\n"; return 1; } boost::asio::io_service io_service; tcp::resolver resolver(io_service); tcp::resolver::query query(argv[1], argv[2]); tcp::resolver::iterator iterator = resolver.resolve(query); chat_client c(io_service, iterator); boost::thread t(boost::bind(&boost::asio::io_service::run, &io_service)); char line[chat_message::max_body_length + 1]; while (std::cin.getline(line, chat_message::max_body_length + 1)) { using namespace std; // For strlen and memcpy. chat_message msg; msg.body_length(strlen(line)); memcpy(msg.body(), line, msg.body_length()); msg.encode_header(); c.write(msg); } c.close(); t.join(); } catch (std::exception& e) { std::cerr << "Exception: " << e.what() << "\n"; } return 0; } chat_server.cpp: // // chat_server.cpp // ~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #include <algorithm> #include <cstdlib> #include <deque> #include <iostream> #include <list> #include <set> #include <boost/bind.hpp> #include <boost/shared_ptr.hpp> #include <boost/enable_shared_from_this.hpp> #include <boost/asio.hpp> #include <boost/thread.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; virtual std::string identifier() = 0; virtual void close() = 0; }; typedef boost::shared_ptr<chat_participant> chat_participant_ptr; //---------------------------------------------------------------------- class releaser { public: virtual ~releaser() {}; virtual void session_release() = 0; }; class chat_room { public: void init(releaser *p) { parent_ = p; } void join(chat_participant_ptr participant) { std::cout << participant->identifier() << " join room " << identifier() << std::endl; participants_.insert(participant); std::for_each(recent_msgs_.begin(), recent_msgs_.end(), boost::bind(&chat_participant::deliver, participant, _1)); std::stringstream ss; ss << participant->identifier() << " join room "; chat_message msg; msg.body_length(ss.str().length()); memcpy(msg.body(), ss.str().c_str(), msg.body_length()); msg.encode_header(); deliver(msg); } void leave(chat_participant_ptr participant) { std::cout << participant->identifier() << " leave room " << identifier() << std::endl; participants_.erase(participant); std::stringstream ss; ss << participant->identifier() << " leave room "; chat_message msg; msg.body_length(ss.str().length()); memcpy(msg.body(), ss.str().c_str(), msg.body_length()); msg.encode_header(); deliver(msg); parent_->session_release(); } void deliver(const chat_message& msg) { recent_msgs_.push_back(msg); while (recent_msgs_.size() > max_recent_msgs) recent_msgs_.pop_front(); std::for_each(participants_.begin(), participants_.end(), boost::bind(&chat_participant::deliver, _1, boost::ref(msg))); } std::string identifier() { return identifier_; } const void identifier(const std::string &str) { identifier_ = str; } std::size_t live_count() const { return participants_.size(); } void close() { std::for_each(participants_.begin(), participants_.end(), boost::bind(&chat_participant::close, _1)); } private: std::set<chat_participant_ptr> participants_; enum { max_recent_msgs = 100 }; chat_message_queue recent_msgs_; std::string identifier_; releaser *parent_; }; //---------------------------------------------------------------------- class chat_session : public chat_participant, public boost::enable_shared_from_this<chat_session> { public: chat_session(boost::asio::io_service& io_service, chat_room& room) : socket_(io_service), io_service_(io_service), room_(room) { } tcp::socket& socket() { return socket_; } void start() { room_.join(shared_from_this()); boost::asio::async_read(socket_, boost::asio::buffer(read_msg_.data(), chat_message::header_length), boost::bind( &chat_session::handle_read_header, shared_from_this(), boost::asio::placeholders::error)); } void deliver(const chat_message& msg) { bool write_in_progress = !write_msgs_.empty(); write_msgs_.push_back(msg); if (!write_in_progress) { boost::asio::async_write(socket_, boost::asio::buffer(write_msgs_.front().data(), write_msgs_.front().length()), boost::bind(&chat_session::handle_write, shared_from_this(), boost::asio::placeholders::error)); } } virtual std::string identifier() { std::stringstream ss; ss << socket_.remote_endpoint().address().to_string() << ":" << socket_.remote_endpoint().port(); return ss.str(); } virtual void close() { io_service_.post(boost::bind(&chat_session::do_close, this)); } void handle_read_header(const boost::system::error_code& error) { if (!error && read_msg_.decode_header()) { boost::asio::async_read(socket_, boost::asio::buffer(read_msg_.body(), read_msg_.body_length()), boost::bind(&chat_session::handle_read_body, shared_from_this(), boost::asio::placeholders::error)); } else { room_.leave(shared_from_this()); } } void handle_read_body(const boost::system::error_code& error) { if (!error) { char buf[chat_message::max_body_length + 1]; memcpy(buf, read_msg_.body(), read_msg_.body_length()); buf[read_msg_.body_length()] ='\0'; std::stringstream ss; ss << identifier() << " say: " << buf; chat_message msg; msg.body_length(ss.str().length()); memcpy(msg.body(), ss.str().c_str(), msg.body_length()); msg.encode_header(); room_.deliver(msg); boost::asio::async_read(socket_, boost::asio::buffer(read_msg_.data(), chat_message::header_length), boost::bind(&chat_session::handle_read_header, shared_from_this(), boost::asio::placeholders::error)); } else { room_.leave(shared_from_this()); } } void handle_write(const boost::system::error_code& error) { if (!error) { write_msgs_.pop_front(); if (!write_msgs_.empty()) { boost::asio::async_write(socket_, boost::asio::buffer(write_msgs_.front().data(), write_msgs_.front().length()), boost::bind(&chat_session::handle_write, shared_from_this(), boost::asio::placeholders::error)); } } else { room_.leave(shared_from_this()); } } private: void do_close() { socket_.close(); } tcp::socket socket_; chat_room& room_; chat_message read_msg_; chat_message_queue write_msgs_; boost::asio::io_service &io_service_; }; typedef boost::shared_ptr<chat_session> chat_session_ptr; //---------------------------------------------------------------------- class chat_server : public releaser { public: chat_server(boost::asio::io_service& io_service, const tcp::endpoint& endpoint) : io_service_(io_service), acceptor_(io_service, endpoint), endpoint_(endpoint) { room_.init(this); std::stringstream ss; ss << endpoint.port(); room_.identifier(ss.str()); chat_session_ptr new_session(new chat_session(io_service_, room_)); acceptor_.async_accept(new_session->socket(), boost::bind(&chat_server::handle_accept, this, new_session, boost::asio::placeholders::error)); } void handle_accept(chat_session_ptr session, const boost::system::error_code& error) { if (!error) { session->start(); //if (room_.live_count() < 2) { chat_session_ptr new_session(new chat_session(io_service_, room_)); acceptor_.async_accept(new_session->socket(), boost::bind(&chat_server::handle_accept, this, new_session, boost::asio::placeholders::error)); //} //else { //acceptor_.close(); //} } } virtual void session_release() { /* open again */ /* * if (room_.live_count() < 2) { acceptor_.open(endpoint_.protocol()); acceptor_.set_option(boost::asio::socket_base::reuse_address(true)); acceptor_.bind(endpoint_); acceptor_.listen(); } */ } void close() { io_service_.post(boost::bind(&chat_server::do_close, this)); room_.close(); } private: void do_close() { acceptor_.close(); } boost::asio::io_service& io_service_; tcp::acceptor acceptor_; chat_room room_; tcp::endpoint endpoint_; }; typedef boost::shared_ptr<chat_server> chat_server_ptr; typedef std::list<chat_server_ptr> chat_server_list; //---------------------------------------------------------------------- int main(int argc, char* argv[]) { try { if (argc < 2) { std::cerr << "Usage: chat_server <port> [<port> ...]\n"; return 1; } boost::asio::io_service io_service; chat_server_list servers; for (int i = 1; i < argc; ++i) { using namespace std; // For atoi. tcp::endpoint endpoint(tcp::v4(), atoi(argv[i])); chat_server_ptr server(new chat_server(io_service, endpoint)); servers.push_back(server); } boost::thread io_thread(boost::bind(&boost::asio::io_service::run, &io_service)); std::string line; while(getline(std::cin, line)) { if (line == "exit") { chat_server_list::iterator it = servers.begin(); for ( ; it != servers.end(); ++it) (*it)->close(); break; } } io_thread.join(); } catch (std::exception& e) { std::cerr << "Exception: " << e.what() << "\n"; } return 0; } step 1: start server step 2: start client, connect to server step 3: on server, type "exit" result: server crashed "This application has requested the Runtime to terminate it in an unusual way. Please contact the application's support team for more information." 2010/3/8 OvermindDL1 <overminddl1@gmail.com>:
On Sun, Mar 7, 2010 at 5:58 PM, l.jay Yuan <pass86@gmail.com> wrote:
in msvcrt.dll
But in the callstack at that point, what is your last code that is called, better to just past the callstack here, or even better, post a complete compilable example that demonstrates your problem.
Also, please do not top-post. _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

If I understand correctly, you work with MSVC. Then you can use its IDE/Debugger to run and debug your server. Just compile your project in "debug" mode, i.e. without optimizations. Remove SEH __try/__except filters/handlers from your code. Go to Debug-->Exceptions menu. In the "Thrown" column select all the list. Now run your server in the IDE and try reproducing the issue. When it occurs and an exception is thrown, the IDE stops and you can analyze the problem. I guess you've got some invalid memory access, so a general recommendation is to avoid the manual control over objects life-time -- instead, use smart-pointers (shared_ptr, shared_from_this idiom); also avoid using c-style arrays -- stick with std::vector instead.

...
step 1: start server step 2: start client, connect to server step 3: on server, type "exit" result: server crashed "This application has requested the Runtime to terminate it in an unusual way. Please contact the application's support team for more information."
Please do not top post (again). Also, no I will not read your code, as its a few hundred lines, so please only post to the list your changes, or the change that triggers your error. regards, Jens Weller -- GRATIS für alle GMX-Mitglieder: Die maxdome Movie-FLAT! Jetzt freischalten unter http://portal.gmx.net/de/go/maxdome01

thanks everyone, i solved my problem. just use io_service.stop() instead of acceptor.close() and socket.close(). maybe i must to research the implementation. 2010/3/10 Jens Weller <JensWeller@gmx.de>:
...
step 1: start server step 2: start client, connect to server step 3: on server, type "exit" result: server crashed "This application has requested the Runtime to terminate it in an unusual way. Please contact the application's support team for more information."
Please do not top post (again).
Also, no I will not read your code, as its a few hundred lines, so please only post to the list your changes, or the change that triggers your error.
regards,
Jens Weller -- GRATIS für alle GMX-Mitglieder: Die maxdome Movie-FLAT! Jetzt freischalten unter http://portal.gmx.net/de/go/maxdome01 _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

thanks everyone, i solved my problem. just use io_service.stop() instead of acceptor.close() and socket.close(). maybe i must to research the implementation.
It's not a solution but just a "dirty" workaround: by stopping io_service you prevent the further invocation of handlers. I guess some of your handlers used to get called after destruction of the object they were bound to. You can avoid this situation by binding the handlers to shared_from_this().

can you code the Boost.Asio chat server example for exit by a command? if you can, my problem solved. 2010/3/10 Igor R <boost.lists@gmail.com>:
thanks everyone, i solved my problem. just use io_service.stop() instead of acceptor.close() and socket.close(). maybe i must to research the implementation.
It's not a solution but just a "dirty" workaround: by stopping io_service you prevent the further invocation of handlers. I guess some of your handlers used to get called after destruction of the object they were bound to. You can avoid this situation by binding the handlers to shared_from_this(). _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

int main(int argc, char* argv[]) { try { if (argc < 2) { std::cerr << "Usage: chat_server <port> [<port> ...]\n"; return 1; } boost::asio::io_service io_service; chat_server_list servers; for (int i = 1; i < argc; ++i) { using namespace std; // For atoi. tcp::endpoint endpoint(tcp::v4(), atoi(argv[i])); chat_server_ptr server(new chat_server(io_service, endpoint)); servers.push_back(server); } io_service.run(); /************** just like this, so io_service.run(); is not needed. boost::thread io_thread(boost::bind(&boost::asio::io_service::run, &io_service)); std::string line; while(getline(std::cin, line)) { if (line == "exit") { /* do what? now i am using io_service.stop(); */ break; } } io_thread.join(); ***************/ } catch (std::exception& e) { std::cerr << "Exception: " << e.what() << "\n"; } return 0; } 2010/3/11 l.jay Yuan <pass86@gmail.com>:
can you code the Boost.Asio chat server example for exit by a command? if you can, my problem solved.
2010/3/10 Igor R <boost.lists@gmail.com>:
thanks everyone, i solved my problem. just use io_service.stop() instead of acceptor.close() and socket.close(). maybe i must to research the implementation.
It's not a solution but just a "dirty" workaround: by stopping io_service you prevent the further invocation of handlers. I guess some of your handlers used to get called after destruction of the object they were bound to. You can avoid this situation by binding the handlers to shared_from_this(). _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

l.jay Yuan wrote:
can you code the Boost.Asio chat server example for exit by a command? if you can, my problem solved.
Please do not top post: http://www.boost.org/community/policy.html#quoting regards - michael -- ---------------------------------- Michael Caisse Object Modeling Designs www.objectmodelingdesigns.com
participants (6)
-
Igor R
-
Jens Weller
-
l.jay Yuan
-
Michael Caisse
-
OvermindDL1
-
Steven Watanabe