我正在聊天。出於某種原因,在其他客戶端之間分發用戶消息時,由Server::msgHandler
組成的字符串在Connection::write
中被async_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
字符串中的分隔符之前添加的,並且每當我嘗試使名稱出現時,它之前的所有內容都將被所有後續內容覆蓋。有時候,回車會變得瘋狂並跳過名稱前面的一些字符,這會進一步複雜化該錯誤的搜索。
我建議初始化的boost ::支持ASIO ::流緩衝buf''與在'Connection'構造......一些內存;) – 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'constructor不爲接收緩衝區分配任何內存:'buf'。你現在明白了麼? – kenba