Forum: PC-Programmierung curl Chunked transfer encoding verträgt sich nicht mit dynamischer IP


von A. R. (redegle)


Lesenswert?

Hallo,

ich verwende die Bibliothek curl mit C++.
curl: http://curl.haxx.se/libcurl/
chunked Verbindung: 
http://en.wikipedia.org/wiki/Chunked_transfer_encoding

Das Programm läuft wie folgt ab.

-Informationsabfrage von einem Server.
-Empfangene Daten werden analysiert und curl wird konfiguriert.
-In einem neuen Thread wird die Bibliothek curl ausgeführt. Dieser baut 
eine Verbindung (Session) mit dem Server aufgebaut. Anschließend erfolgt 
die Antwort als chunked Verbindung. Diese "blockiert" das Programm. 
Deswegen wird die chunked Verbindung in einem neuen Thread ausgeführt. 
Immer wenn Daten empfangen werden wird von curl eine "Writefunction" 
aufgerufen der die Daten zugeschoben werden.
-Im Hauptthread erfolgt eine weitere Kommunikation mit dem Server. 
Dieser Teilt dem Server mit, welche Daten über die chunked Verbindung 
gesendet werden sollen.
-Anschließend wird gewartet bis der Thread beendet wird (Unterbrechung 
des Datentransfers nach ca. 1,5h).
-Das ganze beginnt von vorne.

Zitat aus Wikipedia:
"The last chunk is a zero-length chunk, with the chunk size coded as 0, 
but without any chunk data section."

Problem:
Wenn sich die Ip meines Rechners ändert, während die chunked Verbindung 
aktiv ist werden keine Daten mehr empfangen. Curl bekommt also nicht 
mit, dass die Verbindung beendet worden ist und der Thread läuft endlos 
weiter.

Wie würdet Ihr das Problem lösen?

Ich dachte darüber nach eine Zeitkontrolle einzubauen. Immer wenn Daten 
empfangen werden wird eine Variable gesetzt. Sobald über einen Zeitraum 
von n Sekunden keine Daten empfangen werden wird die Verbindung für tod 
erklärt und der Thread "zwangs"beendet. Dies kommt mir jedoch etwas 
unprofessionell vor.

Habt Ihr Vorschläge, wie man das Problem geschickter lösen kann?

von Εrnst B. (ernst)


Lesenswert?

Ich hatte das mal (allerdings nicht mit Curl) durch das Senden von 
Keep-Alive-Chunks gelöst.
War ne HTML-Anwendung, also konnte ich einfach jede Minute einen
<!-- Kommentar --> über die Leitung jagen.
Heute würd ich das zwar nicht mehr so machen, gibt ja inzwischen mit 
AJAX/WebSocket usw. bessere Möglichkeiten, aber funktioniert hats.

von A. R. (redegle)


Lesenswert?

Ich verstehe nicht so ganz was das mit meinem Problem zu tun hat.

Mein Problem ist ja, dass curl so lange wartet, bis eine Nachricht 
kommt. Aber die kommt nicht.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

A. R. schrieb:
> Wenn sich die Ip meines Rechners ändert, während die chunked Verbindung
> aktiv ist werden keine Daten mehr empfangen

Wie das? Sowas ist nun wirklich nicht vorgesehen, normalerweise sollte 
dann die Verbindung abbrechen.

A. R. schrieb:
> Ich dachte darüber nach eine Zeitkontrolle einzubauen.
> Dies kommt mir jedoch etwas unprofessionell vor.
Wieso? Das ist bei Netzverbindungen das Mittel der Wahl.

A. R. schrieb:
> Im Hauptthread erfolgt eine weitere Kommunikation mit dem Server.

Du könntest eine Art "nop" Kommando definieren, spätestens beim Senden 
sollte auffallen falls die Gegenstelle nicht verfügbar ist.

von A. R. (redegle)


Lesenswert?

>A. R. schrieb:
>> Wenn sich die Ip meines Rechners ändert, während die chunked Verbindung
>> aktiv ist werden keine Daten mehr empfangen

>Wie das? Sowas ist nun wirklich nicht vorgesehen, normalerweise sollte
>dann die Verbindung abbrechen.

Eben genau das passiert nicht. Das ist mein Problem.
Der Thread in dem die chunked Verbindung abläuft wird nicht beendet. Es 
kommt auch keine Fehlermeldung und nichts. Curl wartet einfach auf eine 
Antwort und es kommt nichts. Würde curl mit ner Fehlermeldung abbrechen 
wäre alles Super.

Im Endeffekt starte ich eine Funktion und diese wird nie beendet.

>A. R. schrieb:
>> Ich dachte darüber nach eine Zeitkontrolle einzubauen.
>> Dies kommt mir jedoch etwas unprofessionell vor.
>Wieso? Das ist bei Netzverbindungen das Mittel der Wahl.

Ja das wird bei Netzverbindungen öfterns gemacht. Deswegen frage ich ob 
das so in Ordnung ist oder ob es bessere Möglichkeiten gibt. Ich finde 
es etwas unprefessionell, da bei Zeitabfragen das debuggen extrem 
verschwert wird.
Ich weiß auch nicht, wie ich die curl Verbindung abbrechen soll.
Ich verwende Boost::Thread für Multithreads. Hierbei gibt es keinen 
close Befehl der den Thread zerstört. Zumindest ist mir keine bekannt. 
Curl kann ich auch nicht so ohne weiteres abbrechen. Ich kann es 
pausieren mehr auch nicht.

von Kitkat Chunky (Gast)


Lesenswert?

A. R. schrieb:
> Ich weiß auch nicht, wie ich die curl Verbindung abbrechen soll.
> Ich verwende Boost::Thread für Multithreads. Hierbei gibt es keinen
> close Befehl der den Thread zerstört. Zumindest ist mir keine bekannt.

Ist auch besser so. Einen Thread einfach so rauszuschießen ist keine 
gute Idee, besonders wenn C++, Auto-variablen mit Konstruktoren, Mutexe 
usw. im Spiel sind.

> Curl kann ich auch nicht so ohne weiteres abbrechen. Ich kann es
> pausieren mehr auch nicht.

Versuch mal die CURLOPT_PROGRESSFUNCTION zu setzen. Da solltest du bei 
jedem internen Curl-Poll/select-Schleifenlauf einen Aufruf kriegen, und 
kannst von dort aus komfortabel auf Timeout warten und auch die 
Verbindung/curl sauber beenden.

von A. R. (redegle)


Lesenswert?

Schoneinmal vielen vielen Dank für die Information.
Wenn ich das auf der Homepage von curl richtig interpretiere ist das 
genau das was ich suche. Damit hast du mir richtig geholfen.
1
CURLOPT_PROGRESSFUNCTION
2
3
Function pointer that should match the curl_progress_callback 
4
prototype found in <curl/curl.h>. This function gets called by 
5
libcurl instead of its internal equivalent with a frequent 
6
interval during operation (roughly once per second or sooner) 
7
no matter if data is being transfered or not. Unknown/unused 
8
argument values passed to the callback will be set to zero 
9
(like if you only download data, the upload size will remain 0). 
10
Returning a non-zero value from this callback will cause libcurl 
11
to abort the transfer and return CURLE_ABORTED_BY_CALLBACK.
12
13
If you transfer data with the multi interface, this function will 
14
not be called during periods of idleness unless you call the 
15
appropriate libcurl function that performs transfers.
16
17
CURLOPT_NOPROGRESS must be set to 0 to make this function 
18
actually get called.

Dort kann ich dann abfragen ob innerhalb der letzten n Sekunden eine 
Antwort vom Server kam (jede Sekunde kommt etwas, wenn auch nur ein keep 
alive). Wenn nicht kommt breche ich einfach curl ab. Somit muss ich dann 
auch nichts in der main verändern.

[edit]
Bitte /code/-Abschnitte manuell umbrechen, sie sind sonst nicht sinnvoll 
lesbar.

-rufus

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

A. R. schrieb:
> Ich verwende Boost::Thread für Multithreads.
> Hierbei gibt es keinen
> close Befehl der den Thread zerstört.

Das üblich Pattern ist folgendes:
1
run() {
2
  while(!this.stop) {
3
   //do something
4
  }
5
}
6
7
stopOperation() {
8
 this.stop = true;
9
}
Man darf dann natürlich nicht mit blockierenden Operationen arbeiten. 
Einige Threadbibliotheken unterstützen auch das Konzept des Thread 
interupts, sodass man einen Thread auch in blockierenden Operation aus 
dem Schlaf reißen kann:
1
run() {
2
 try {
3
  data = blockingRead();
4
 } catch(ThreadInteruptionException) {
5
   //interupted while running...
6
 }
7
}

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.