boost async tcp client

J'ai juste commencé à travailler avec boost.
Je suis de l'écriture TCP client-serveur avec async sockets.

La tâche est la suivante:

  1. Client envoie au serveur un certain nombre
  2. Client peut envoyer un autre nubmer avant de recevoir la réponse du serveur.
  3. Serveur reçoit un numéro, faire un peu de calcul et renvoie le résultat au client.
  4. Plusieurs clients peuvent être connectés à un serveur.

Fonctionne désormais la suivante

  • envoyer un numéro de client pour rompre
  • serveur reçoit un certain nombre de thread en cours et calcule droit dans le OnReceive gestionnaire (je sais c'est mal...mais comment je dois commencer un nouveau thread pour faire le calcul en parallèle)
  • serveur envoie la réponse en arrière, mais le client déjà déconnecté

Comment peut autoriser le client à saisir des nombres au clavier et à attendre une réponse du serveur en même temps?

Et pourquoi est-ce que mon client de ne pas attendre la réponse de rompre?

Le code de client:

using boost::asio::ip::tcp;
class TCPClient
{
public:
TCPClient(boost::asio::io_service& IO_Service, tcp::resolver::iterator EndPointIter);
void Close();
private:
boost::asio::io_service& m_IOService;
tcp::socket m_Socket;
string m_SendBuffer;
static const size_t m_BufLen = 100;
char m_RecieveBuffer[m_BufLen*2];
void OnConnect(const boost::system::error_code& ErrorCode, tcp::resolver::iterator EndPointIter);
void OnReceive(const boost::system::error_code& ErrorCode);
void OnSend(const boost::system::error_code& ErrorCode);
void DoClose();
};
TCPClient::TCPClient(boost::asio::io_service& IO_Service, tcp::resolver::iterator EndPointIter)
: m_IOService(IO_Service), m_Socket(IO_Service), m_SendBuffer("")
{
tcp::endpoint EndPoint = *EndPointIter;
m_Socket.async_connect(EndPoint,
boost::bind(&TCPClient::OnConnect, this, boost::asio::placeholders::error, ++EndPointIter));
}
void TCPClient::Close()
{
m_IOService.post(
boost::bind(&TCPClient::DoClose, this));
}
void TCPClient::OnConnect(const boost::system::error_code& ErrorCode, tcp::resolver::iterator EndPointIter)
{
cout << "OnConnect..." << endl;
if (ErrorCode == 0)
{
cin >> m_SendBuffer;
cout << "Entered: " << m_SendBuffer << endl;
m_SendBuffer += "\0";
m_Socket.async_send(boost::asio::buffer(m_SendBuffer.c_str(),m_SendBuffer.length()+1),
boost::bind(&TCPClient::OnSend, this,
boost::asio::placeholders::error));
} 
else if (EndPointIter != tcp::resolver::iterator())
{
m_Socket.close();
tcp::endpoint EndPoint = *EndPointIter;
m_Socket.async_connect(EndPoint, 
boost::bind(&TCPClient::OnConnect, this, boost::asio::placeholders::error, ++EndPointIter));
}
}
void TCPClient::OnReceive(const boost::system::error_code& ErrorCode)
{
cout << "receiving..." << endl;
if (ErrorCode == 0)
{
cout << m_RecieveBuffer << endl;
m_Socket.async_receive(boost::asio::buffer(m_RecieveBuffer, m_BufLen),
boost::bind(&TCPClient::OnReceive, this, boost::asio::placeholders::error));
} 
else 
{
cout << "ERROR! OnReceive..." << endl;
DoClose();
}
}
void TCPClient::OnSend(const boost::system::error_code& ErrorCode)
{
cout << "sending..." << endl;
if (!ErrorCode)
{
cout << "\""<< m_SendBuffer <<"\" has been sent" << endl;
m_SendBuffer = "";
m_Socket.async_receive(boost::asio::buffer(m_RecieveBuffer, m_BufLen),
boost::bind(&TCPClient::OnReceive, this, boost::asio::placeholders::error));
}
else
{
cout << "OnSend closing" << endl;
DoClose();
}
}
void TCPClient::DoClose()
{
m_Socket.close();
}
int main()
{
try 
{
cout << "Client is starting..." << endl;
boost::asio::io_service IO_Service;
tcp::resolver Resolver(IO_Service);
string port = "13";
tcp::resolver::query Query("127.0.0.1", port);
tcp::resolver::iterator EndPointIterator = Resolver.resolve(Query);
TCPClient Client(IO_Service, EndPointIterator);
cout << "Client is started!" << endl;
cout << "Enter a query string " << endl;
boost::thread ClientThread(boost::bind(&boost::asio::io_service::run, &IO_Service));
Client.Close();
ClientThread.join();
} 
catch (exception& e)
{
cerr << e.what() << endl;
}
cout << "\nClosing";
getch();
}

Ici, elle est sortie de la console

Client is starting...
Client is started!
OnConnect...
12
Entered: 12
sending...
"12" has been sent
receiving...
ERROR! OnReceive...
Closing

Partie serveur

class Session
{
public:
Session(boost::asio::io_service& io_service)
: socket_(io_service)
{
dataRx[0] = '\0';
dataTx[0] = '\0';
}
tcp::socket& socket()
{
return socket_;
}
void start()
{
socket_.async_read_some(boost::asio::buffer(dataRx, max_length),
boost::bind(&Session::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void handle_read(const boost::system::error_code& error, size_t bytes_transferred)
{
cout << "reading..." << endl;
cout << "Data: " << dataRx << endl;
if (!error)
{
if (!isValidData())
{
cout << "Bad data!" << endl;
sprintf(dataTx, "Bad data!\0");
dataRx[0] = '\0';
}
else
{
sprintf(dataTx, getFactorization().c_str());
dataRx[0] = '\0';
}
boost::asio::async_write(socket_,
boost::asio::buffer(dataTx, max_length*2),
boost::bind(&Session::handle_write, this,
boost::asio::placeholders::error));
}
else
{
delete this;
}
}
void handle_write(const boost::system::error_code& error)
{
cout << "writing..." << endl;
if (!error)
{
cout << "dataTx sent: " << dataTx << endl;
dataTx[0] = '\0';
socket_.async_read_some(boost::asio::buffer(dataRx, max_length),
boost::bind(&Session::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
else
{
delete this;
}
}
string getFactorization() const
{
//Do something
}
bool isValidData()
{
locale loc; 
for (int i = 0; i < strlen(dataRx); i++)
if (!isdigit(dataRx[i],loc))
return false;
return true;
}
private:
tcp::socket socket_;
static const size_t max_length = 100;
char dataRx[max_length];
char dataTx[max_length*2];
};
class Server
{
public:
Server(boost::asio::io_service& io_service, short port)
: io_service_(io_service),
acceptor_(io_service, tcp::endpoint(tcp::v4(), port))
{
Session* new_session = new Session(io_service_);
acceptor_.async_accept(new_session->socket(),
boost::bind(&Server::handle_accept, this, new_session,
boost::asio::placeholders::error));
}
void handle_accept(Session* new_session, const boost::system::error_code& error)
{
if (!error)
{
new_session->start();
new_session = new Session(io_service_);
acceptor_.async_accept(new_session->socket(),
boost::bind(&Server::handle_accept, this, new_session,
boost::asio::placeholders::error));
}
else
{
delete new_session;
}
}
private:
boost::asio::io_service& io_service_;
tcp::acceptor acceptor_;
};
int main(int argc, char* argv[])
{
cout << "Server is runing..." << endl;
try
{
boost::asio::io_service io_service;
int port = 13;
Server s(io_service, port);
cout << "Server is run!" << endl;
io_service.run();
}
catch (boost::system::error_code& e)
{
std::cerr << e << "\n";
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}

Du serveur de sortie

Server is runing...
Server is run!
reading...
Data: 12
writing...
dataTx sent: 13    //just send back received ++number
reading...
Data:

Votre aide sera très appréciée

========

Ajouté

Ok, je comprends. Mais vérifiez ErrorCode == boost::asio::erreur::eof ne fonctionne pas... Qu'ai-je fait de mal?

else if (ErrorCode == boost::asio::error::eof)
{
cout << "boost::asio::error::eof in OnReceive!" << endl;
}
else 
{
cout << "ERROR! OnReceive..." << ErrorCode << endl;
DoClose();
}

L'impression est ERROR! OnReceive...system:10009 il semble être ma comparaison est incorrect

========

Ajouté

J'ai trouvé la cause. J'ai déjà mentionné l'utilisation async_receive (au lieu de async_read_some) et swaped les lignes dans main à

ClientThread.join();
Client.Close();

Maintenant il fonctionne très bien!

Maintenant, je suis en train de lire et écrire des données à partir de/à la prise en même temps (parce que le client doit être en mesure d'envoyer des demandes supplémentaires avant la réponse du serveur est reçu.

Dans OnConnect fonction que j'ai créer boost threads:

boost::thread addMsgThread(boost::bind(&TCPClient::addMsgLoop, this));
boost::thread receivingThread(boost::bind(&TCPClient::startReceiving, this));
boost::thread sendingThread(boost::bind(&TCPClient::startSending, this));

avec inplementation

void TCPClient::startReceiving()
{
cout << "receiving..." << endl;
m_RecieveBuffer[0] = '\0';
m_Socket.async_receive(boost::asio::buffer(m_RecieveBuffer, m_BufLen),
boost::bind(&TCPClient::receivingLoop, this, boost::asio::placeholders::error)); //runtime error here
cout << "m_RecieveBuffer = " << m_RecieveBuffer << endl;
}
void TCPClient::receivingLoop(const boost::system::error_code& ErrorCode)
{
cout << "receiving..." << endl;
if (ErrorCode == 0)
{
cout << "m_RecieveBuffer = " << m_RecieveBuffer << endl;
m_Socket.async_receive(boost::asio::buffer(m_RecieveBuffer, m_BufLen),
boost::bind(&TCPClient::receivingLoop, this, boost::asio::placeholders::error));
}
else 
{
cout << "ERROR! receivingLoop..." << ErrorCode << endl;
DoClose();
}
}
void TCPClient::addMsgLoop()
{
while (true)
{
string tmp;
cin >> tmp;
cout << "Entered: " << tmp << endl;
tmp += "\0";
try
{
msgQueue.push(tmp);
}
catch(exception &e)
{
cerr << "Canno add msg to send queue... " << e.what() << endl;
}
}
}

Le problème est le même avec les deux receive et send threads: erreur d'exécution (écrit violation d'accès quelque part dans les bibliothèques boost).

void TCPClient::startReceiving()
{
...
m_Socket.async_receive(); //runtime error here
}

Dans sequent version tout fonctionne très bien (mais je ne sais pas comment la mettre plusieurs d'envoi avant de répondre).
Quelqu'un peut-il me dire comment résoudre la question ou comment mettre en œuvre cette par un autre chemin? Peut être mise en commun peut aider, mais je suis maintenant convaincu que c'est le bon sens.

Dans OnReceive vous devez vérifier quelle est l'erreur que vous obtenez, il peut dire ce qu'est le problème.
Et bien sûr vérifier le côté serveur, pour voir ce qui s'y passe.
Débogage d'erreur s'affiche 10009
Réfléchissez un peu: m_SendBuffer += "\0"; (Indice: Quelle est la différence entre "\0" et ""?) Aussi, si vous allez utiliser read_some, c'est votre travail pour vous assurer que vous avez reçu un ensemble au niveau de l'application message.

OriginalL'auteur Torrius | 2012-10-20