COLORREF to char*- gibt's was schnelleres als stringstreams?
-
andi01 schrieb:
hm welche der methoden ist denn am schnellsten? memcpy() oder casten?
da ich das ganze in einer schleife ziemlich oft mache ist die Performance wichtig
Nö. Da du es nachher über's Netz (vermute mal Internet) verschickst ist die Performance eher nicht so wichtig.
Davon abgesehen: wäre vielleicht klüger wenn du gleich ein ganzes Bild auf einmal verschickst?
-
hustbaer schrieb:
Nö
naja ein geschicktes Bild hat mehrere megapixel, wenn man diese Konvertierung also mehrere Millionen mal ausführt dauert es mit stringstreams ca. 10sec, mit beiden oberen methoden ca. 2sek.
ich würde mal sagen dass sich eine Verzögerung von 8sek ganz deutlich merken lässt

hustbaer schrieb:
wäre vielleicht klüger wenn du gleich ein ganzes Bild auf einmal verschickst?
ja, Problem dabei ist dass die Funktion send() nur char* als Parameter akzeptiert und keine fertigen bmp- oder jpeg-dateien^^
deshalb bin ich dazu übergegegangen einen screenshot praktisch "zeilenweise" zu verschicken:
zB schreibe ich erstmal den COLORREF-Wert aller Pixel in der "Zeile" y=0, also der obersten Zeile am Bildschirm, in einen char* pointer mit ; getrennt und schicke diese "Zeilen" einzeln weg, bis ich bei der letzten angekommen bin.
bessere Methoden sind mir allerdings immer willkommen, auch wenn mit grade keine bessere einfällt

-
Jo,
Denk auch an die MTU (Maximum transition Unit), für ne maximale auslastung solltest du ca 1430 bytes auf einmal verwenden, (je nach router einstellung, bei mir {wegen PPP} 1492-40=1452 Nutzdaten), falls Du über 1460 kommst wird der restliche teil in einem seperaten Paket verschickt und der rest mit nullen aufgefüllt bis die minimale paketgröße erreicht ist....
Also net zu viel und net zu wenig auf einmal verschicken

-
andi01 schrieb:
hustbaer schrieb:
wäre vielleicht klüger wenn du gleich ein ganzes Bild auf einmal verschickst?
ja, Problem dabei ist dass die Funktion send() nur char* als Parameter akzeptiert und keine fertigen bmp- oder jpeg-dateien^^
nö.
send ist in dieser hinsicht wie "remote memcpy".
da man ein BMP/JPG/PNG/... problemlos mit memcpy kopieren kann, kann man es auch mit send() versenden. also generell alles was in einem file steht bzw. als 1:1 abbild eines files im speicher steht kann man mit send() verschicken.
natürlich sollte man vorher die grösse mitschicken, damit der empfänger auch weiss wie lange das "file" ist.
schnapp dir also eine library die halbwegs flott bilder komprimieren kann (mit oder ohne verlust, ganz nach belieben) und verschick dann das ganze bild auf einmal.
p.S.: wenn du unkomprimiert verschicken willst, dann solltest du vermutlich einfach alle relevanten bytes in ein grosses char-array packen, und das dann auf einmal verschicken. die COLORREFs direkt zu verschicken macht weniger sinn, da ein COLORREF ein DWORD ist, also 4 byte gross. wobei aber nur 3 relevant sind.
@zeusosc:
"zu viel" ist eher unproblematisch, zumindest wenn es "viel zu viel" ist. wenn ich ein 1 MB stück an send() übergeben wird das u.U. sogar schneller rausgehen als wenn ich das gleiche datenstück in lauter 14xx byte stücken übergebe.
-
wenn man mal stark vereinfach davon ausgeht dass eine "zeile" zB aus 5 Pixeln besteht und jedes Pixel dieselbe Farbe hat (beispielsweise 1234567) steht in der zu sendenden char* Variable folgendes:
1234567;1234567;1234567;1234567;1234567
also ich würde die Größe so ausrechnen(korrigiert mich bitte wenn ich falsch liege):
sizeof(COLORREF) gibt 4 zurück, deswegen nehme ich mal an dass COLORREF im Speicher 4 Bytes belegt genau wie ein ; in einer char* variable;
(jetzt geht's schon richtig in Mathe über
)sagen wir mal n ist die Anzahl der Pixel pro Zeile:
das heißt die Größe aller COLOREREF-Werte wäre 4n;
die anzahl der Strichpunkte ist n-1;
größe der Strichpunkte ist also 4*(n-1);d.h. die Gesamtgröße in Bytes liegt bei 4n+4*(n-1) = 4*[n+(n-1)] = 4*(2n-1);
edit: muss ich eigentlich das \0 am Ende mitrechnen?
msdn schrieb:
int send(
__in SOCKET s,
__in const char *buf,
__in int len,
__in int flags
);( http://msdn.microsoft.com/en-us/library/ms740149 )
der 2.Parameter ist doch eindeutig vom Typ char* -> man kann auch nur daten vom typ char* verschicken oder liege ich da falsch?

edit2: gibt es eigentlich irgendeine vorgerfertigte Methode um éinen Screen zu machen? aktuell lese ich nämlich jedes Pixel einzeln^^
edit 3: ist es jetzt performancemäßig besser die char* in bestimmte Stücke zu teilen oder als ein char* zu schicken?
danke schonmal,
andi01.
-
@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