boost::asio::io_service und asynchrones schreiben von Daten

Der Wolf

Erfahrenes Mitglied
Hi Leute,

ich experimentiere in meiner Freizeit gerade mit der boost::asio library und der Kommunikation zwischen Clients und einem Server herum. Dazu habe ich mir die Beispiele auf der Boost Seite angeschaut und versucht das in einer eigenen App um zu setzen.
Mein Problem ist nun, der Server akzeptiert die Anfrage von Clients zwar, aber wenn ich Daten vom Client an den Server senden will, passiert anscheinend einfach garnichts. Zumindest wird der zuständige completion-handler nicht aufgerufen. Da ich schon seit einiger Zeit daran sitze und keine Lösung finde, hoffe ich, dass mir hier jemand weiter helfen kann.

Starten des Clients in der main Methode:
Code:
void startClient(boost::asio::io_service &service, const std::string hostname) {

	std::cout << "Starting client." << std::endl;
	Client *client = new Client(hostname, service);

	std::cout << "Starting io service." << std::endl;
	boost::thread t(boost::bind(&boost::asio::io_service::run, &service));

	while (true) {
	
		char line[255];
		std::cout << "Please insert message: ";
		std::cin.getline(line, 256);
		client->send(line);	
	
	}

}

Und der Source-Code des Clients:

Code:
#include "Client.h"
#include "Message.h"
#include "Configurations.h"

#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <strings.h>
#include <netdb.h>

#include <iostream>
#include <string.h>

// ==========================================================================
// Public stuff.
// ==========================================================================

Client::Client(const std::string &hostname, boost::asio::io_service &ioService) : ioService(ioService) {

	// Resolve the ip address from the hostname.
	boost::asio::ip::tcp::resolver resolver(ioService);
	boost::asio::ip::tcp::resolver::query query(hostname, "4814");

	// Create a socket for the connection.
	socket = new boost::asio::ip::tcp::socket(ioService);

	// Try each found endpoint.
	boost::asio::ip::tcp::resolver::iterator iter = resolver.resolve(query);
	boost::asio::ip::tcp::resolver::iterator end;

	boost::asio::ip::tcp::endpoint endpoint = *iter;
	socket->async_connect(endpoint, boost::bind(&Client::handleConnect, 
						this, boost::asio::placeholders::error, ++iter));

	msg = NULL;

}

Client::Client(boost::asio::ip::tcp::socket *socket) : ioService(socket->io_service()) {
	this->socket = socket;
}

Client::~Client() {
}

void
Client::send(const std::string message) {

	if (msg)
		delete msg;

	// Constructs message from assigned content.
	msg = new Message(message);
  ioService.post(boost::bind(&Client::write, this, msg));

}

// ==========================================================================
// Private stuff.
// ==========================================================================

void
Client::handleConnect(const boost::system::error_code &error,  
							boost::asio::ip::tcp::resolver::iterator endpoint_iterator) {

	if (!error) {
		std::cout << " 1 " << std::endl;
	} else if (endpoint_iterator != boost::asio::ip::tcp::resolver::iterator()) {
		std::cout << " 2 " << std::endl;
	}

}

void 
Client::write(Message *msg) {

	std::cout << "Hallo" << std::endl;

	boost::asio::async_write(*socket,
		boost::asio::buffer(msg->data, msg->getLength()),
  	        boost::bind(&Client::handleWrite, this, boost::asio::placeholders::error));

}

void
Client::handleWrite(const boost::system::error_code &error) {

	if (error)
		std::cerr << "Could not send message" << std::endl;

}

Gruß
Der Wolf
 
Hi.

Mach mal bitte ein vollständiges Programm. Und sag vor allem auch was die Eingabe und Ausgabe deines Programmes ist.

Gruß
 
Hi,

also ich habe das Projekt mal auf den Client/Server Part zusammengestrichen - nicht, dass da bisher viel mehr existierte, aber sonst hätte man zum compilieren noch die Irrlicht-Engine haben müssen ;) - und es verpackt. Nebenbei sei noch gesagt, dass ich im Moment unter Ubuntu 10.04 experimentiere und zum kompilieren cmake und make verwende. Die Boost-Library ist version 1.40.
Nach dem Komplieren kannst du den Server starten indem du die Tmp.exe ohne Parameter aufrufst. Den Client kann man starten mit bin/Tmp localhost oder dem Rechner wo der Server läuft. Der Port über den Kommuniziert wird ist 4814.
Eigentlich sollte man auf der Server Seite, nach der Eingabe einer Nachricht sehen, dass da etwas passiert und die Länge des Nachrichten bodies sollte angegeben werden. Auf Client Seite sollte ein "Hallo" stehen (tut es bei mir aber nicht).
Ich tippe fast darauf, dass es wieder irgendwas simples ist, was ich einfach nur nicht sehe. ;)
 

Anhänge

  • App.zip
    26,9 KB · Aufrufe: 23
Ich denke ich habe das Problem gefunden.

Das "Problem" liegt an der io_service::run() Methode, die ich einem separaten Thread aufrufe. Diese Methode kehrt zurück sobald sie "nichts mehr zutun hat", dass heisst, wenn es keine asynchronen Methoden gibt, die noch aufgerufen wurden.

Nachdem man Client sich mit dem Server verbunden hat, sind alle asynchronen Methoden abgearbeitet gewesen und die run() Methode kehrt zurück, der Thread wird also beendet. Damit wird auch keine weitere asynchrone Methode ausgeführt und daher wird auch nach dem Aufruf von client->send() der completion-handler nicht aufgerufen.

Gruß
Der Wolf
 
Zurück