Ich arbeite an einem Chat. Aus irgendeinem Grund wird die durch Server::msgHandler
von Server::msgHandler
zusammengesetzte Zeichenfolge an dem Punkt, an dem die Benutzernachricht zwischen anderen Clients verteilt wird, durch async_write
in Connection::write
zerlegt, wodurch sie so aussieht, als ob nur der Teil dieser Zeichenfolge tatsächlich gelesen wurde. Beispiel:boost :: async_write überspringt Teile der Zeichenfolge
Konstruiert Nachricht: "Hallo Leute von Jack"
Erscheint als: "Jack"
, die die string str=Hello people
ist nicht ausgedruckt. Zuerst dachte ich, es wäre mit dem impliziten \0
an seinem Ende zu tun, aber das würde keinen Sinn machen, außerdem, als ich verschiedene Positionen der Zeichenfolge in der Nachricht versuchte ich festgestellt, dass, wenn str
mit anderem Text vorangestellt ist, wird der Text gezeigt werden, entweder str
vollständig ausstrahlend, oder es an unerwarteten Plätzen platzierend. Z.B.
writeMsg("It was said: \n"+str+" by \"name\"\n");
wird wie folgt angezeigt:
Es wurde gesagt
von "name" Hallo Leute
voll, minimal, übersetzbar Beispiel:
#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
Die async_read
wurde die Zeichenfolge mit Carriage Return angefügt, die gespeichert wurde, wie es vor dem Delimeter in der Zeichenfolge name
hinzugefügt wurde, und jedes Mal, wenn ich versuchte, den Namen erscheinen, alles davor würde durch alle folgenden überschrieben werden. Manchmal würde der Wagenrücklauf wild werden und einige Zeichen vor dem Namen überspringen, was die Suche nach diesem Fehler weiter kompliziert.
Ich empfehle Initialisierung boost :: asio :: streambuf buf'' mit einigen Speicher in dem 'Connection' Konstruktor ...;) – kenba
@ kenba 'streambuf' hat keine Konstruktoren, keine Funktionen, die für das Zuweisen von Speicher zu seinen Objekten definiert sind, also weiß ich nicht wirklich, was Sie sagen. Ich benutze 'basic_streambuf' nicht –
' streambuf'' ist eine Instanz von [basic_streambuf] (http://www.boost.org/doc/libs/1_64_0/doc/html/boost_asio/reference/basic_streambuf/basic_streambuf.html) . Der 'Connection'Constructor reserviert keinen Speicher für den Empfangspuffer:' buf'. Verstehst du es jetzt? – kenba