Seite 1 von 2
Socketprogrammierung high-optimized
Verfasst: 9. Juni 2008 18:09
von KartoffelKiffer
Hallo,
wir haben zurzeit zwei Programme laufen, die sich über einen Socket miteinander unterhalten. Programm A ist unter Qt 3.11 geschrieben und sendet mittels QSocket und QTextStream eine Mitteilung an Programm B, geschrieben in Qt 4.4.0.
Dabei wird in Programm A ein Connect im Konstruktor aufgebaut und über die Funktion SendMessage(QString) eine Mitteilung an Programm B gesendet.
Programm B liest diese Mitteilung ein, sobald ein SIGNAL(readyRead()) aus der "nextPendingConnection" eintrifft. Diese Message wird per
Code: Alles auswählen
QString msg = "";
QTextStream is(m_ClientConnection); // InputStream
msg.append(is.readAll());
eingelesen.
Rufe ich nun direkt 3x hintereinander die Funktion SendMessage auf, so kommt in Programm B lediglich eine Mitteilung an. Der Inhalt besteht aus Mitteilung 1 + Mitteilung 2 + Mitteilung 3 gesendet aus Programm A.
Nun habe ich mit einem Arbeitskollegen gesprochen, der meinte, dass das Betriebssystem und auch TCP/IP hochoptimiert arbeitet, was Traffic angeht. Das OS "sieht" also, das Programm A möchte gern etwas direkt hintereinander senden, packt die drei Mitteilungen also in ein Paket zusammen und verschickt es als solches?
Interessant dabei ist noch, dass wenn ich hinter die SendMessage-Funktionen in Programm A einen Breakpoint setze, und langsam durchsteppe, in Programm B erst etwas angezeigt wird, sobald die letzte Message aus Programm A versendet wurde.
Über eine Lösung des Problems, oder auch Hinweise bin ich sehr gespannt und natürlich auch dankbar.
Mfg KK
Verfasst: 9. Juni 2008 18:14
von Christian81
Du kannst das nicht verhindern - Du musst dich um solche Dinge (messages splitten) schon selbst kümmern.
Warum es beim Debuggen auch nicht geht liegt wohl daran, dass Du kein flush() machst und es alles noch in irgend einen Buffer vor sich hinschlummert. Aber wie gesagt - hilft Dir eh nichts zur Lösung deines Problems.
Verfasst: 9. Juni 2008 19:58
von MiKla
unter Windows (WinApi) (Linux wahrscheinlich auch) gibt es:
Code: Alles auswählen
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
damit wird jedes Paket sofort rausgeschickt, dass heisst es wird nicht es gesammelt bis der Frame groß genug ist.
Ob es in Qt 'ne Option dafür gibt weiss ich nicht.
Verfasst: 9. Juni 2008 20:08
von MiKla
hab noch das gefunden:
Code: Alles auswählen
/* Disable the Nagle (TCP No Delay) algorithm ON UNIX PLATFORMS */
int sockID, flag, ret;
sockID = yourQTcpSocket->socketDescriptor();
flag = 1;
ret = setsockopt( sockID, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, sizeof(flag) );
if (ret == -1) {
// error while trying to disable the nagle optimization
}
/* Disable the Nagle (TCP No Delay) algorithm ON WINDOWS PLATFORMS */
SOCKET sockId = yourQTcpSocket->socketDescriptor();
int ret;
BOOL bOptVal = true; // seems to be true here, but not completely sure.
ret = setsockopt(sockID, IPPROTO_TCP, TCP_NODELAY, (char*)&bOptVal, sizeof(bool))
if ( ret == SOCKET_ERROR) {
// error while trying to disable the nagle optimization
int error = WSAGetLastError(void);
}
vielleicht hilft's weiter
Verfasst: 9. Juni 2008 20:11
von PeterLustig
@Michael.Klank
Deine Hilfsbereitschaft in Ehren, aber
- Benutz doch bitte die Editierfunktion

Dafür ist sie da
- Das hier ist ein Qt Forum, er programmiert mit Qt, es geht um Qt, warum also Code von der puren Socket API? Die wird nicht im geringsten helfen
- Christian hat den Befehl bereits genannt: flush
Verfasst: 9. Juni 2008 20:18
von MiKla
@Michael.Klank
Deine Hilfsbereitschaft in Ehren, aber
- Benutz doch bitte die Editierfunktion Smile Dafür ist sie da
- Das hier ist ein Qt Forum, er programmiert mit Qt, es geht um Qt, warum also Code von der puren Socket API? Die wird nicht im geringsten helfen
- Christian hat den Befehl bereits genannt: flush
http://www.qtcentre.org/forum/f-qt-prog ... -3037.html
ist vielleicht doch nicht soweit weg

Verfasst: 9. Juni 2008 21:20
von solarix
Nun habe ich mit einem Arbeitskollegen gesprochen, der meinte, dass das Betriebssystem und auch TCP/IP hochoptimiert arbeitet, was Traffic angeht. Das OS "sieht" also, das Programm A möchte gern etwas direkt hintereinander senden, packt die drei Mitteilungen also in ein Paket zusammen und verschickt es als solches?
Das OS sieht das zwar nicht, aber die Wahrscheinlichkeit ist einfach hoch, dass man mehr als nur ein paar Bytes versenden möchte... Die Treiber optimieren also so nach "best practice"...
Ein wichtiger Punkt noch: die Frames einzeln zu versenden ist (in diesem Fall) idiotisch, weil die Daten auf der Empfangsseite ja wieder zusammengeführt werden (OS sammelt die Eingangsdaten in einem Empfangsbuffer). D.h., du kannst auch einmal Message 1 und die Hälfte von Message 2 im Puffer haben (bei grossen Messages sogar wahrscheinlich)!
Betrachte das ganze also als "Stream" und definiere ein eigenes Protokoll (wie schon von Chr. vorgeschlagen).
Verfasst: 9. Juni 2008 21:39
von MiKla
Das OS sieht das zwar nicht, aber wie Wahrscheinlichkeit ist einfach hoch, dass man mehr als nur ein paar Bytes versenden möchte... Die Treiber optimieren also so nach "best practice"...
Ein wichtiger Punkt noch: die Frames einzeln zu versenden ist (in diesem Fall) idiotisch, weil die Daten auf der Empfangsseite ja wieder zusammengeführt werden (OS sammelt die Eingangsdaten in einem Empfangsbuffer). D.h., du kannst auch einmal Message 1 und die Hälfte von Message 2 im Puffer haben (bei grossen Messages sogar wahrscheinlich)!
Das sehe ich nicht ganz so. In meinem Fall war es so, dass ich alle 60ms ein TCP Paket (16 Bytes) an eine SPS verschicken mußte (Bilderkennung, Druckmarke). Ohne "TCP_NODELAY" hat das OS die Nachrichten gesammelt und dann erst verschickt. Das war in diesem Fall tötlich, weil die SPS eine Druckmarkenregelung macht und so nicht mehr sichergestellt war, dass das TCP Paket zur Druckmarke gepasst hat.
Verfasst: 9. Juni 2008 22:15
von solarix
es war klar, dass sowas kommt... ich habe das "in diesem Fall" nicht einfach so aus Langeweile geschrieben..
Verfasst: 10. Juni 2008 19:22
von KartoffelKiffer
Seid gegrüßt. Ein simples flush() hat die Sache schonmal verbessert, aber nicht behoben. Über kurz oder lang werde ich nicht drum herum kommen, ein eigenes Protokoll zu schreiben.
Schonmal besten Dank für die Hilfe!
Mfg KK
Verfasst: 11. Juni 2008 14:21
von Markus
Sind es nur Strings, die zwischen den Programmen verschickt werden? Wenn ja, dann kannst Du ein CR/LF anhängen, wenn die Daten in den Socket gehen und auf der Gegenseite einfach mit canReadline() und readLine() die Daten zeilenweise abholen.
Verfasst: 14. Juni 2008 14:25
von KartoffelKiffer
Hallo Markus,
ja es sind bloß Strings, habe es nun so gelöst, wie Du gesagt hast. Guter Einfall, danke!
Mfg KK
Verfasst: 9. Juli 2008 17:13
von KartoffelKiffer
Hallo,
ich habe noch etwas die Anwendung getestet, da genau dieser Engpass in einer weiteren Applikation aufgetreten ist.
Ich sende jede Millisekunde eine Mitteilung an den Server ab.
Dabei ist folgende Variante am Schnellsten gewesen:
Code: Alles auswählen
void DataIfc::IncomingMessage()
{
QString buffer = "";
QTextStream is(m_ClientConnection); // InputStream
buffer.append(is.readAll());
QStringList splitted = buffer.split("\n");
QString message = "";
for (int i = 0; i < splitted.size(); ++i)
{
message = splitted.at(i);
if (message.length() > 0)
{
emit GotData(message);
}
}
}
Wobei bei jedem Senden ein \n hinter den String geschrieben werden muss.
Lese ich den Text per readLine() aus, bekomme ich genau 400 Mitteilungen in der Sekunde mit, bei der o.g. sind es genau 500. Was mir allerdings noch auffällt, ich muss in der for-Schleife die Abfrage auf Größe > 0 machen, da bei mir einige leere Strings dazwischen waren. Ungefähr jeder zweite (was den anderen 500 Mitteilungen entsprechen würde).
Ich hoffe damit trotzdem noch jemandem geholfen zu haben.
Mfg KK
Verfasst: 9. Juli 2008 23:47
von solarix
Ich hoffe damit trotzdem noch jemandem geholfen zu haben.
Und ich hoffe, dass dieser Code von niemandem kopiert wird.. denn bei
Code: Alles auswählen
buffer.append(is.readAll());
QStringList splitted = buffer.split("\n");
dürfte die letzte Meldung jeweils unvollständig sein.. besonders wenn die Meldungen i.d.R. grösser sind..
Verfasst: 10. Juli 2008 08:15
von MiKla
Sollten dann nicht bei 1 Message/ 1ms = 1000 Messages /s sein und nicht 500 Messages/s ???