COLORREF to char*- gibt's was schnelleres als stringstreams?
-
@hustbÄr:
Jo richtig, ich meinte auch nur wenn es sich halt immer um einen minimalen overflow handelt
-
@zeusosc: selbst bei minimalem "overflow" sollte sich nagle's algorithm darum kümmern dass nicht VIEL zu viele pakete verschickt werden.
send-send-send ist ziemlich unproblematisch.
send-send-recv kann dagegen zu deutlichen delays führen.(wobei mir natürlich klar ist dass irgendwann fast immer ein recv kommt, nur wenn der datenfluss selten genug die richtung wechselt, dann kommt man mit paketen beliebiger grösse eigentlich recht gut durch)
-
kurzfassung: vergiss dass der typ "char*" ist.
der zeiger den du da übergibst ist einfach der anfang eines datenblocks (byte-array), und die länge die du übergibst ist die länge dieses datenblocks in bytes.
(ich hab ehrlich gesage keine ahnung was auf systemen wo char nicht 8 bit hat passiert, also ob die beschreibung der sockets API darauf überhaupt eingeht, aber diese systeme vergessen wir einfach mal. zahlt sich nicht aus darüber nachzudenken.)
und was ist ein file? ein file ist auch ein datenblock, ein ding was aus lauter bytes besteht. also kannst du alles was du in ein file schreiben kannst auch über nen socket schicken.
so einfach ist das.
was COLORREF angeht: angenommen du hast ein array aus 100 COLORREF und willst die *relevanten* daten da drin übertragen:
void foo() { COLORREF cols[100]; // EDIT: hier irgendwie daten nach "cols" reinladen // EDIT: 100 COLORREFs "serialisieren" (ginge auch mit nem fixed-size buffer, da wir hier fix 100 COLORREFs == 300 bytes verschicken) std::vector<unsigned char> buffer; for (size_t i = 0; i < 100; i++) { buffer.push_back(GetRValue(cols[i])); buffer.push_back(GetGValue(cols[i])); buffer.push_back(GetBValue(cols[i])); } // macht genau 3 byte pro COLORREF assert(buffer.size() == 300); int const rc = send( socket_handle, reinterpret_cast<char const*>(&buffer[0]), buffer.size(), flags); // ... }easy-peasy
wenn du auf der gegenseite dieses datenstück wieder in ein COLORREF array verwandeln willst, ist das auch nicht schwer
void bar() { unsigned char buffer[300]; // wir kennen die grösse ja unsigned char* recv_ptr = buffer; int recv_outstanding = 300; // 300 bytes vom client empfangen // NOTE: die schleife BRAUCHT man, siehe beschreibung von recv() // (man kann nicht verhindern dass recv() nur ein teil-stück empfängt, // und dann schon zurückkehrt, daher muss man selber "mitzählen" wieviel // schon empfangen wurde und ggf. weitere recv() aufrufe nachschieben) while (recv_outstanding > 0) { int const rc = recv( socket_handle, reinterpret_cast<char*>(recv_ptr), // EDIT: reinterpret_cast hat hier gefehlt recv_outstanding, flags); if (rc == 0) { // gegenstelle hat "aufgelegt" -> irgendwie handeln // ... } else if (rc < 0 || rc > recv_outstanding) { // FEHLER -> irgendwie handeln assert(rc == SOCKET_ERROR); // ... } else { // ein stück daten wurde empfangen (und zwar "rc" bytes) recv_outstanding -= rc; // fehlt jetzt weniger recv_ptr += rc; // was noch fehlt muss "weiter hinten" im puffer landen // und weiter mit dem nächsten stück... } } // und wieder 100 COLORREFs draus machen COLORREF cols[100]; for (size_t i = 0; i < 100; i++) cols = RGB(buffer[3 * i], buffer[3 * i + 1], buffer[3 * i + 2]); // EDIT: hier stand "col = " statt "cols = " - vertipper // ferdisch }
-
andi01 schrieb:
edit 3: ist es jetzt performancemäßig besser die char* in bestimmte Stücke zu teilen oder als ein char* zu schicken?
es wird überhaupt nirgends ein "char*" verschickt. ein "char*" ist ein ZEIGER, der ZEIGT nur auf die daten die verschickt werden.
genauso kannst du zum verschicken der daten den "char*" nicht zerteilen.du kannst nur den datenblock in mehrere datenblöcke "zerteilen", und dann jeden einzeln schicken.
lern bitte dich genauer auszudrücken, das ewigt rumraten "was könnte der noob damit jetzt gemeint haben" ist auf die dauer sehr lästig.
die antwort auf deine frage ist: es ist besser alles auf einmal zu verschicken.
-
kann ich dann nicht gleich auch COLORREF-Werte wegschicken? dann kann ich mir doch das Konvertieren sparen und gleich eine Zeile als COLORREF-Vector wegschicken oder?
also ungefähr so:
vector<COLORREF> zeile; for(int a=0;a<1200;a++)//mal angenommen 1200 pixel pro zeile { zeile.push_back(GetPixel(GetDC(0), a, 0)); } send(socket, reinterpret_cast<const char*> (zeile), zeile.size(), 0);
-
Jo, aber dann sendest du halt ein Byte überflüssig mit, denn COLORREF = unsigned long = 4 Bytes, ein RGB Wert wird aber mit nur 3 Bytes dargestellt.
-
beim Rückkonvertieren macht das aber hofentlich nichts aus oder?
ok aber wie kriege ich jetzt die empfangenen bytes wieder nach COLORREF?
wenn ich nur immer einen colorref-wert sende wäre es klar:
COLORREF recieved; char* a=new char[sizeof(COLORREF)]; recv(socket, reinterpret_cast<COLORREF>(a), sizeof(recieved), 0);aber wie mache ich das jetzt wenn ich den bei send() nach char* gecasteten vektor wieder als COLORREF haben will?
so?:
vector<COLORREF> zeile; char* a=new char[sizeof(COLORREF)]; recv(socket, reinterpret_cast<COLORREF>(a), sizeof(recieved), 0);
-
Du benutzt die Variable "zeile" gar nicht

Wenn immer ein send und recv zusammengehören (kA, hab damit nix am Hut), dann einfach:
// send unsigned long color; send(socket, reinterpret_cast<const char*>(&color), sizeof(unsigned long), 0); // receive unsigned long color; recv(socket, reinterpret_cast<char*>(&color), sizeof(unsigned long), 0);
-
Checker! schrieb:
Du benutzt die Variable "zeile" gar nicht

Wenn immer ein send und recv zusammengehören (kA, hab damit nix am Hut), dann einfach:
// send unsigned long color; send(socket, reinterpret_cast<const char*>(&color), sizeof(unsigned long), 0); // receive unsigned long color; recv(socket, reinterpret_cast<char*>(&color), sizeof(unsigned long), 0);send(socket, reinterpret_cast<const char*>(&color), sizeof(unsigned long), 0);... ein bisschen kurz die nachricht oder ?
grüüße
-
ja klar, wenn ich nur einen COLORREF-Wert gleichzeitig senden würde könnte ich das so machen.
das problem ist doch dass ich den vector<COLORREF> mit mehreren Werten einfach nach const char* gecastet und verschickt habe;
d.h. ich kann das von recv() empfangene(nämlich mehrere COLORREF-Werte) doch nicht in eine COLORREF-Variable stecken

irgendwie muss das doch auch wieder in einen vector oder zumindest ein array...
edit: davon mal ganz abgesehen kann ich nicht einfach einen vector nach char* casten, der Kompiler sagt nämlich selbst bei einem reinterpret_cast eine Lonvertierung sei unmöglich.
obige Möglichkeit zum Senden ist demnach falsch. muss ich also jedes einzelne element des vektor extra casten und senden oder wie geht das dann?
also meine Lösung würde momentan so aussehen:
//send: for(int y=0;y<1500;y++) { for(int x=0;x<1500;x++) { COLORREF farbe=GetPixel(GetDC(0), x, y); send(socket, reinterpret_cast<const char*>(farbe), sizeof(COLORREF), 0); } } //recv: for(int y=0;y<1500;y++) { for(int x=0;x<1500;x++) { COLORREF farbe; char* empfangen=new char[sizeof(COLORREF)]; recv(socket, empfangen, sizeof(COLORREF), 0); farbe=reinterpret_cast<COLORREF>(farbe); } }stimmt das dann so?
-
Lies noch mal die letzten beiden Beiträge von @hustbaer.
zB.
// send unsigned long colors[3] = { 1, 2, 3 }; send(socket, reinterpret_cast<const char*>(colors), sizeof(colors), 0); // receive unsigned long colors[3]; recv(socket, reinterpret_cast<char*>(colors), sizeof(colors), 0);
-
in meinem code hat noch ein reinterpret_cast gefehlt, sowie ein vertipper war drin. hab ich nachgetragen sowie noch ein paar kommentare hinzugefügt.
und flags ist üblicherweise 0 für alle die sich wundern was sie da mitgeben sollen.
@Checker!:
siehe nachgetragenes kommentar vor der recv()-schleife: die braucht man, sonst bekommt man (schwer zu debuggende) probleme. recv() wartet nämlich nicht bis "size" bytes empfangen wurden, sondern kommt u.u. schon zurück nachdem erst ein byte empfangen wurde.
-> schleife
-
andi01 schrieb:
edit: davon mal ganz abgesehen kann ich nicht einfach einen vector nach char* casten, der Kompiler sagt nämlich selbst bei einem reinterpret_cast eine Lonvertierung sei unmöglich.
kauf dir ein C++ buch und lern erstmal die grundlagen.
oder schreib wenigstens richtig ab:
std::vector<MEIN_POD_TYP> vec; v.push_back(MEIN_POD_TYP(1)); v.push_back(MEIN_POD_TYP(2)); v.push_back(MEIN_POD_TYP(3)); char* char_ptr = reinterpret_cast<char*>(&vec[0]); // so geht's //char* char_ptr = reinterpret_cast<char*>(vec); // so nicht
-
@hustbaer
Achso, aber nur mit dem TCP, oder?
-
so, ich habe jetzt mal versucht hustbaers codebeispiel auf S.2 zu kompilieren, foo() funktioniert, bei bar() kommt aber noch ein Fehler vom Compiler in Z.44:
MS Visual C++ 2008 EE schrieb:
(44) : error C2440: '=': 'COLORREF' kann nicht in 'COLORREF [100]' konvertiert werden
sollte wahrscheinlich cols[i] heißen

ich teste es mal schnell ob das senden jetzt geht
-
@hustbÄR:
Hi,
ich habe schon öfters gesehen dass auf den datenbereich von STL Komponenten referenziert wird, man sollte aber nicht davon ausgehen dass der allocierte Speicherbereich von STL' komponenten in Reihe liegt. Sollte es nämlich zu einer höheren fragmentation des Heaps kommen, wäre die folge das bei der iteration deines gecasteten ptr'S ein bekanntes 0x00000005 kommt.Ansonsten braucht man auch kein reinterpret_cast, sondern kopiert ainfach die addresse von einem pointer zum anderen....(Wenn der inhalt nicht konvertiert werden soll...)
Es gäbe aber noch eine Alternative:
typedef union _ta{ COLORREF _farbe; char a[4]; } BLUB,*LPBLUB; LPBLUB _sendMeBabY=(LPBLUB)malloc(12*sizeof(COLORREF)); _sendMeBabY[0]._farbe=0x0044444; char* _Snd=(_sendMeBabY[0].a); //Speicher bereich: //a[0]= 0x44 //a[1]= 0x44 //a[2]= 0x04 //a[3] = 0x00Seid gegrüßt und einen schönen tag der Arbeit

-
@zeusosc
So richtig hässlich!
Es ist garantiert, dass die Elemente von std::vector im Speicher hintereinander liegen.
-
zeusosc schrieb:
@hustbÄR:
Hi,
ich habe schon öfters gesehen dass auf den datenbereich von STL Komponenten referenziert wird, man sollte aber nicht davon ausgehen dass der allocierte Speicherbereich von STL' komponenten in Reihe liegt. Sollte es nämlich zu einer höheren fragmentation des Heaps kommen, wäre die folge das bei der iteration deines gecasteten ptr'S ein bekanntes 0x00000005 kommt.Falsch. Der Standard garantiert dieses Verhalten, und alle STL Implementierungen die ich kenne setzen das auch korrekt um.
Ansonsten braucht man auch kein reinterpret_cast, sondern kopiert ainfach die addresse von einem pointer zum anderen....(Wenn der inhalt nicht konvertiert werden soll...)
Es gäbe aber noch eine Alternative:
typedef union _ta{ COLORREF _farbe; char a[4]; } BLUB,*LPBLUB; LPBLUB _sendMeBabY=(LPBLUB)malloc(12*sizeof(COLORREF)); _sendMeBabY[0]._farbe=0x0044444; char* _Snd=(_sendMeBabY[0].a); //Speicher bereich: //a[0]= 0x44 //a[1]= 0x44 //a[2]= 0x04 //a[3] = 0x00Sinnloser Scheissendreck. Und AFAIK ist nichtmal garantiert dass es funktioniert.
-
Bezüglich "Union Hack":
Sinnloser Scheissendreck. Und AFAIK ist nichtmal garantiert dass es funktioniert.
Korrekt, das ist nicht garantiert. Garantiert ist nur dass lesen/schreiben von derselben Variable funktioniert.
Simon
-
Punkt a)
Stimmt, ich habe den random access mit der alloc fkt verwechselt,.. srytemplate<class _Ty> inline _Ty _FARQ *_Allocate(_SIZT _Count, _Ty _FARQ *) { // check for integer overflow if (_Count <= 0) _Count = 0; else if (((_SIZT)(-1) / _Count) < sizeof (_Ty)) _THROW_NCEE(std::bad_alloc, NULL); // allocate storage for _Count elements of type _Ty return ((_Ty _FARQ *)::operator new(_Count * sizeof (_Ty))); }Punkt b)
Mir wÄr unklar das das nicht funktionieren sollte,..
Union == Überlappender Speicherbereich ?Und wenn ihr angst vor char a[4] habt weil sonst ja der ptr auf die addresse des wertes zeigt nemmt ihr halt vier char, davon abgesehen ist der Kompiler schlau genug den ptr des char array's auf den gleichen speicherbereich von der colorref variablen zu legen.
Also nochmal die Frage: Warum sollte das nicht gehen?
grüüße