Komunikator p2p z wykorzystaniem boost.asio

0

Witam!

Chce napisać komunikator, który umożliwia komunikację pomiędzy dwa hostami w sieci lokalnej. Moim zamierzeniem jest napisać prostego klienta, prosty serwer i wrzucić to do dwóch wątków, tak aby możliwe było jednoczesne odbieranie i wysyłanie danych. Napisałem, krótki kod, który już działa jednak mam problem z paroma rzeczami.

Po pierwsze chciałbym to opakować w klasy. Czyli dla serwera i klienta tworzymy klase i w zależności co chcemy mieć tworzymy dwa obiekty za pomocą, różniących się minimalnie konstruktorów(np. bool czy_serwer = true). I tutaj głównie problem polega na implementacji tego w Boost.Asio. Jesli ktoś ma jakieś wskazówki, gotowe przykłady itp. byłbym wdzięczy. (główny problem to wątki i współbieżne działanie obiektu klienta i serwer)

Kolejną rzeczą jest wysyłanie wiadomości. Przed wysłaniem wiadomość szyfruję i wtedy strona odbierająca musi ją rozszyfrować(to już mam wstępnie zaimplementowane). Jednocześnie pisząc i odbierając wiadomości w konsoli, tekst się może niestey nałożyć na siebie(napisze połowe wiadomości i w tym momencie odbieram nową). Dlatego chce korzystać z np. ncurses i każdą wiadomość odebraną wyświetlać w wyodrębnionym fragmencie konsoli. Mam tutaj problem jak dostać się do każdej wiadomości odbieranej przez serwer(zmienna globalna?).

Wrzucam kod serwera i klienta który mam. Każda wskazówka, rada, link (i gotowe rozwiązania takżę! :) ) będą cenne.

#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/array.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp> 
#include <boost/thread.hpp>
#include <iostream>
#include <string>
const int size_buff = 30;
void nadaj(std::string host, int port) {
		std::string message;
		boost::asio::io_service ios;
		boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::address::from_string(host), port);
		boost::array<char, size_buff> buf;
		
		while (true) {
			std::getline(std::cin, message, '\n');
			if(message.length()>=(size_buff-1)){
				message.erase(size_buff-1);
			}
			message += "\n";
			
			boost::asio::ip::tcp::socket socket(ios);
			socket.connect(endpoint);
			std::copy(message.begin(),message.end(),buf.begin());
			boost::system::error_code error;
			socket.write_some(boost::asio::buffer(buf, message.size()), error);
			
			message.clear();
			socket.close(); 
		}
}

size_t read_complete(char * buff, const boost::system::error_code & err, size_t bytes) {
	if ( err) return 0;
	bool found = std::find(buff, buff + bytes, '\n') < buff + bytes;
	return found ? 0 : 1;
}

void odbior(std::string host, int port) {
	boost::asio::io_service service;
	boost::asio::ip::tcp::acceptor acceptor(service, boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(host), port));
	char buff[size_buff];
	while ( true) {
	boost::asio::ip::tcp::socket sock(service);
	acceptor.accept(sock);
	int bytes = read(sock, boost::asio::buffer(buff), boost::bind(read_complete,buff,_1,_2));
	std::string msg(buff, bytes-1);
	std::cout << msg << std::endl;
	//memset( buff, 0, sizeof(buff) );
	sock.close();
	}
}

int main()
{
	boost::thread t1(nadaj, "127.0.0.1", 1990);
	boost::thread t2(odbior, "127.0.0.1", 1990);
	
    t1.join();
    t2.join();

}
 
0

Nie potrzebujesz wątków. Boost Asio bardzo dobrze wspiera programowanie asynchroniczne na jednym wątku. Podejrzyj sobie np. kod serwera http i zobacz jakich rozwiązań użyli: http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/examples/cpp11_examples.html
W razie problemów pytaj:)

0

Przede wszystkim jeśli piszesz w asio to dlaczego nie użyjesz proactor pattern? Proactor (o ile to możliwe) zredukuje liczbę wątków do 1 przez co będziesz miał tylko 1 obiekt io_service. Innymi słowy będziesz musiał miał jednego polla/selecta.
Po drugie dlaczego nie chciało ci się poszukać na własną rękę przykładów kodu w asio? Boost ma bardzo dobrą dokumentację, więc nie trudno o jakiś snippet: http://www.boost.org/doc/libs/1_57_0/doc/html/boost_asio/examples/cpp11_examples.html [szczególnie przykład chata].
Po trzecie nie potrzebujesz używać zmiennych globalnych. Musisz tylko jakoś przekazywać otrzymywane od serwera wiadomości do jakiś obiektów, które komunikują się z właściwą częścią aplikacji (tą, która ma wyświetlać je w danej części okna).

1 użytkowników online, w tym zalogowanych: 0, gości: 1