私はチャットを行っています。何らかの理由で、他のクライアント間でユーザーのメッセージを配信する時点で、Server::msgHandler
で囲まれた文字列がasync_write
でConnection::write
に破棄され、その文字列の一部のみが実際に読み取られたように見えます。例:boost :: async_writeは文字列の一部をスキップします
構築メッセージ:
"ジャックによってこんにちは人々は" のように表示されます。プリントアウトされていないstring str=Hello people
です
"ジャックで"。最初は暗黙的な\0
の最後であると思っていましたが、それでも意味がありませんでした。メッセージの中で文字列のさまざまな位置を試してみましたが、str
の前に他のテキストがある場合、完全にstr
を放出するか、予期しない場所に置くかのどちらかを示してください。例えば。
writeMsg("It was said: \n"+str+" by \"name\"\n");
として表示されます:#include <boost/asio.hpp> #include <boost/bind/bind.hpp> #include <boost/enable_shared_from_this.hpp> #include <iostream> #include <vector> #include <deque> typedef boost::asio::io_service io_service; typedef boost::asio::ip::tcp tcp; class Server; class Connection : public boost::enable_shared_from_this<Connection> { io_service::strand strand; tcp::socket soc; std::deque<std::string> msgBuff; boost::asio::streambuf buf; Server* server; void(Server::*serverHandler)(std::string); private: Connection(io_service& service) :soc(service), strand(service){ } void writeStranded(std::string msg){ msgBuff.push_back(msg); if (msgBuff.size() > 1)return; write(); } void write(){ std::string& tmpMsg = msgBuff[0]; boost::asio::async_write( soc, boost::asio::buffer(tmpMsg.c_str(), tmpMsg.size()), strand.wrap( boost::bind(&Connection::handleWrite, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred) ) ); } void handleWrite(const boost::system::error_code&, size_t s){ msgBuff.pop_front(); if (!msgBuff.empty())write(); } void handleRead(const boost::system::error_code&, size_t s){ std::istream is(&buf); std::string tmpMsg; std::getline(is, tmpMsg); (server->*serverHandler)(tmpMsg); readMsg(); } public: typedef boost::shared_ptr<Connection> pointer; static pointer createInstance(io_service& service){ return pointer(new Connection(service)); } void init(Server* server, void(Server::*serverHandler)(std::string)){ this->server = server; this->serverHandler = serverHandler; writeMsg("hello\n"); readMsg(); } void writeMsg(std::string msg){ strand.dispatch(boost::bind(&Connection::writeStranded, this, msg)); } void readMsg(){ const char delim = '\n'; boost::asio::async_read_until(soc, buf, delim, boost::bind(&Connection::handleRead, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } tcp::socket& getSocket(){ return soc; } }; class Server{ tcp::acceptor accept; std::vector<Connection::pointer> connections; public: Server(io_service& io_service, int port = 23) :accept(io_service, tcp::endpoint(tcp::v4(), port)){ awaitConnection(); }; private: void awaitConnection(){ Connection::pointer con = Connection::createInstance(accept .get_io_service()); accept.async_accept(con->getSocket(), boost::bind(&Server::conAcceptor, this, con, boost::asio::placeholders::error)); } void conAcceptor(Connection::pointer con, const boost::system::error_code& err){ if (err)return; con->init(this, &Server::msgHandler); awaitConnection(); connections.push_back(con); } void msgHandler(std::string str){ for (Connection::pointer ptr : connections){ ptr->writeMsg(str+" by \"name\"\n"); } } }; int main(){ io_service io_service; Server s(io_service); io_service.run(); system("pause"); }
UPD:それは完全な、最小限、コンパイルの例では、 "名前" による
こんにちは人々
を言われた
async_read
は、name
文字列の区切り文字の前に追加されたように保存されたキャリッジリターンの文字列を追加していました。名前を表示しようとするたびに、その前にあるすべての行が上書きされます。キャリッジリターンがワイルドになり、名前の前にいくつかの文字がスキップされることがあり、このバグの検索がさらに複雑になることがあります。
は、私はブーストを初期化をお勧め:: ASIO ::ストリームバッファ 'Connection'のコンストラクタで、いくつかのメモリを搭載したbuf'' ...;) – kenba
@ kenba 'streambuf'には、オブジェクトにメモリを割り当てるためのコンストラクタも関数も定義されていないので、あなたが何を言っているのか分かりません。 'basic_streambuf'を使用していません –
' streambuf'は[basic_streambuf](http://www.boost.org/doc/libs/1_64_0/doc/html/boost_asio/reference/basic_streambuf/basic_streambuf.html)のインスタンスです。 。 'Connection'コンストラクタは受信バッファのためにメモリを割り当てません:' buf'。あなたは今理解していますか? – kenba