Serwer - Boost::Asio

0

Witam. Mam problem z serwerem w booscie, tzn. to jest kod:

Serwer:
int main()
{
	try
	{
		boost::asio::io_service IO_Service;
		tcp::acceptor Acceptor(IO_Service, tcp::endpoint(tcp::v4(), PORT));

		while (true)
		{
			tcp::socket Socket(IO_Service);
			Acceptor.accept(Socket);

			char Data[1024];
			memset(Data, 0, 1024);

			boost::system::error_code Error;
			size_t Lenght = Socket.read_some(boost::asio::buffer(Data), Error);
			std::cout << Data << std::endl;

			if (Error == boost::asio::error::eof)
				break;
			else if (Error)
				std::cout << "Error - " << Error << std::endl;
		}
	}
	catch (std::exception& Error)
	{
		std::cout << Error.what() << std::endl;
	}

	return 0;
}

Client:
int main()
{
	boost::asio::io_service IO_Service;
	boost::asio::ip::tcp::socket Socket(IO_Service);
	boost::asio::ip::tcp::resolver Resolver(IO_Service);

	boost::asio::connect(Socket, Resolver.resolve({ IP, PORT }));

	boost::asio::write(Socket, boost::asio::buffer("123", strlen("123")));
	boost::asio::write(Socket, boost::asio::buffer("456", strlen("456")));
}

W outpucie serwera dostaję "123456" zamiast najpierw "123" i w następnym obrocie "456". Mógłby ktoś wytłumaczyć czemu tak się dzieje? Coś robię źle czy tak po prostu już jest? Jak mam to oddzielić bez bawienia się w dzielenie stringów?

I jeszcze jedno, czym różnią się te funkcje?

boost::asio::read(Socket, boost::asio::buffer(Data, Lenght));
size_t Lenght = Socket.read_some(boost::asio::buffer(Data), Error);
0

W outpucie serwera dostaję "123456" zamiast najpierw "123" i w następnym obrocie "456". Mógłby ktoś wytłumaczyć czemu tak się dzieje? Coś robię źle czy tak po prostu już jest?

Jest to całkowicie normalna rzecz dla protokołu TCP, którego używasz pod maską. TCP daje gwarancję "in-order" wysłanych bajtów tzn. jeśli nadawca wyśle 123456 odbiorca otrzyma również 123456 a nie np. 213456. Niestety TCP nie daje gwarancji, że twoje dwa write-y tj. write(123) i write(456) po stronie nadawcy zawsze zmapują się na dwa read-y (read(123) i read(456)) po stronie odbiorcy. W skrajnych przypadkach odbiorca być może będzie musiał wykonać 6 read-ów lub 1.

Jak mam to oddzielić bez bawienia się w dzielenie stringów?

Niestety Asio udostępnia tylko proste mechanizmy typu wyślij/odbierz zbudowane na bazie UDP/TCP, nie wspiera komunikacji opartej na wiadomościach. Możesz to rozwiązać na kilka sposobów:

  1. Zostać przy Boost.Asio i zaimplementować mechanizm prostych paczek danych tj. najpierw wysyłać długość danych, a poźniej same dane. Czyli nadawca robi write(6), write("123456"). Odbiorca robi read-a, najpierw wyciąga wielkość paczki (6), a potem ciąg read-ów aż do wczytania całej paczki (czyli 6-u bajtów).
    Rozwiązanie dość prymitywne ale IMO najprostsze i najrozsądniejsze (choć na krótką mete).

  2. Zostać przy Boost.Asio i zaimplementować mechanizm msg-ów wraz z serializacją i deserializacją. Podobnie jak wyżej, ale zamiast jednolitych paczek wysyłamy całe obiekty różnych klas. Można się wesprzeć biblioteką Boost.Serialization lub Protobuf.
    Rozwiązanie bardziej czasochłonne niż poprzednie ale daje dużo radochy:)

  3. Zrezygnować z Boost.Asio na rzecz biblioteki zoorientowanej na komunikację typowo msg-ową np. ZeroMQ. To rozwiązanie z kolei jest dobre na "poszerzenie horyzontów" ale wymaga korzystania z biblioteki o zupełnie odmiennym API od tego z Boost.Asio.

0

I jeszcze jedno, czym różnią się te funkcje?
...

Dokumentacja twoim przyjacielem

boost::read(Socket, boost::buffer(Data, Lenght));

http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/reference/read/overload1.html

size_t Lenght = Socket.read_some(boost::buffer(Data), Error);

http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/reference/basic_stream_socket/read_some/overload1.html

Czyli w skrócie - read blokuje do momentu aż zapcha cały bufor wczytanymi danymi (lub sfailuje). Read_some blokuje do momentu aż wczyta przynajmiej jeden bajt (lub sfailuje).

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