Wpis z mikrobloga

#programowanie #qt #cpp

Mirki, orientujecie się może jak i czy się da w ogóle wysłać przez QTcpSocket wektor danych? Ogółem obiekt? W sensie daję mu wektor który ma 100 intów czy czegokolwiek i mu mówię, żeby mi go po prostu wysłał taki jaki jest a ktoś po stronie klienta spodziewa się tego wektora o takim rozmiarze? Czy muszę mu serializować to i odczytywać po prostu tego inta jednego za drugim i po drugiej stronie też łapać jednego inta na raz?
  • 19
@Khaine:

QByteArray block;
QDataStream sendStream(█, QIODevice::ReadWrite);
sendStream << quint16(0) << str;
sendStream.device()->seek(0);
sendStream << (quint16)(block.size() - sizeof(quint16));
tcpSocket->write(block);
@Dymoslaw: Chwila chwila. Mam wektor. Nie QVector tylko std::vector. Taki mamy dziwaczny wymóg, że trzeba jakiejś klasy STLa użyć i tutaj nawet wypada to zrobić. W żadnym innym miejscu programu się w sumie nawet nie da. Program wyłapuje mi bufory dźwięku, które chcę przepisywać do wektora i potem wypluwać przez sieć.

Mogę to zrobić z palca i wysyłać to z buta - w pętli for robić socket->write potem socket->flush int za
@Khaine
Lepiej serializować, ale jeżeli już musisz (jeżeli to np są sample i ważna jest latencja) to w QDataStream masz writeBytes i wrzucasz writeBytes( reinterpret_cast(wektor.data()), wektor.size() * sizeof( decltype(wektor)::value_type ) )
@lionbest: Tak, są to sample. Otrzymuję je od QAudioProbe w QAudioBuffer. Ten QAudioBuffer chcę przepisać do wektora, już najlepiej w osobnym wątku żeby nie tracić czasu (aczkolwiek paczka sampli przychodzi co 0,18 sekundy więc powinien zdążyć sam wewnątrz siebie to przepisać i wysłać gotowca). Gdy wątek skończy przepisywać ma dać znać kolejnemu wątkowi - serwerowi, że pod tym wskaźnikiem ma coś co ma wysłać. I jest to std::vector. Nie coś miłego
@Khaine: Pamiętaj że TCP nie ma paczkowania, dlatego musisz sobie zapisać ile tych danych wysyłasz. O ile binarnie dane nie ma problemu aby wysłąć, to QDataStream przydaje się do opisania nagłówka i daje możliwość ich wysłania. Jest to dużo bezpieczniejsze od klecenia samemu własnego protokołu.
@Khaine: Lol, czy ja coś mówiłem o pliku? Mówiłem ze vectora możesz potraktorać jako ciągłą pamięć korzystając w C++11 z methody data, najlepiej kożystająć z QDataStream::writeBytes które tak naprawdę zapisuje quint32 z rozmiarem i dopiero robi QDataStream::writeRawData, dzięki temu nawet jak się byteorder na innej maszynie odwróci to sam protokół się nie #!$%@? tylko poprawnie odczyta ten bufor, a co w nim będzie to sobie możesz też przesłać.
@Khaine:
1. Transmisja po TCP odbywa się porcjami, i druga strona musi cały przekaz sobie "poskładać" - dlatego aby to było możliwe podałem Ci wyżej prosty sposób: najpierw wysyłasz ilość przesyłanych danych, a dopiero potem same dane binarne.

2. W std::vector jest możliwy bezpośredni dostęp do poszczególnych elementów sekwencyjnie, nawet z wykorzystaniem arytmetyki wskaźników. link, dysponując więc wskaźnikiem na pierwszy element wektora (metoda data()) masz dostęp w zasadzie do kolejnych
@Dymoslaw: Nadal nie mogę sobie tego poskładać. Po kolei.

QByteArray block; // tworzysz jakiś blok danych binarnych, ok

QDataStream sendStream(█, QIODevice::ReadWrite); // tworzysz data stream, który ma zapisywać do bloku w trybie obustronnym

sendStream << quint16(0) << str; // wg. dokumentacji zamiast (0) powinna być chyba liczba, którą chcę tam dodać, nie? Więc musiałbym zrobić fora i element po elemencie wektora w ten sposób wrzucać zdaje się. Czym jest str?

sendStream.device()->seek(0);
@Khaine: masz tu zobrazowane co i jak (to jest tylko fragment - pominąłem celowo sprawy związane z QTcpSocket:
1. void send(const std::vector* buffer) {

2. QByteArray block;
3. QDataStream sendStream(█, QIODevice::ReadWrite);
4. sendStream << quint16(0) << buffer->data();
5. sendStream.device()->seek(0);
6. sendStream << (quint16)(block.size() - sizeof(quint16));
7. tcpSocket->write(block);
}
block - ciąg bajtów na dane do wysyłki skojarzone ze strumieniem (linia 2 i 3)
wysłanie do strumienia: 0, a następnie ciągu intów
@Dymoslaw: Aaa, no wystarczyło powiedzieć, że to jest cofnięcie się na początek. Już kumam wszystko.

Tylko teraz pytanie - jak z odczytem tego? Chcę to wpisać do wektora potem mając byte array. No po prostu rekonstrukcja.
@Khaine:
Robisz rekonstrukcje w slocie podpiętym pod sygnał readyRead klasy QTcpSocket.
Wykorzystujesz QDataStream aby odczytać najpierw wartość przesłanych danych, a następnie te dane do QByteArray.
Na zakończenie odbudowujesz sobie std::vector z QByteArray
@lionbest: Akurat to QByteArray jest nawet wygodne, bo mogę na samym początku jakieś informacje jeszcze do tego wrzucić, np. ile jest kanałów, jakie próbkowanie itd.