Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   Delphi TCP Socket (+ HTTP_GET) möglichst ohne Komponenten (https://www.delphipraxis.net/141978-tcp-socket-http_get-moeglichst-ohne-komponenten.html)

chri_ri 20. Okt 2009 04:31


TCP Socket (+ HTTP_GET) möglichst ohne Komponenten
 
Hi erstmal^^
Also wie der Titel schon sagt suche Ich eine Möglichkeit eine TCP-Kommunikation möglichst ohne Komponenten wie z.B. Indy zu realisieren.

Mein Ziel ist ein möglichst kleines Programm, welches "nur" per HTTP_GET Daten abruft und speichert.

Möchte deshalb auf Formulare verzichten und nur in der Projekt-Datei (*.dpr) arbeiten, da Sie nicht benötigt werden und das Programm so klein wie möglich halten.



Das Problem ist:
Ich habe bisher nur mit Komponenten gearbeitet und weiß nicht, wie ich dies nun anpacken soll.

Habe versucht IdHTTP ohne eigenes Formular zu nutzen. Es funktioniert zwar aber ich erhalte viele verschiedenartige Fehlermeldungen.
Und sobald ich den Eintrag "Forms" aus der uses-Klausel entferne funktioniert es logischerweise garnicht mehr.


Nachdem ich eine Weile gegooglet hatte fand ich auch Codebeispiele für "Komponentenlose" TCP-Programmierung.
Jedoch war eines nicht wirklich funktionsfähig und das andere ließ sich nicht wirklich auf die Nutzung ohne "Extra-Unit" anpassen (oder zumindest hab ichs ned ganz hingekriegt).

Noch 'ne Frage: WinSock = WinAPI?




Wäre eigentlich schon sehr dankbar, wenn mich jemand in die richtige Richtung weißen würde, wonach ich suchen soll und/oder ein paar gute/weiterführende Links posten könnte.

Schonmal Vielen Dank im Vorraus!
Solche Fragen wurden sicher schon oft genug gestellt aber irgendwie find ich ned so recht, was ich suche.

wicht 20. Okt 2009 08:19

Re: TCP Socket Programmierung möglichst ohne Komponenten
 
Moin,

habe jetzt keine Zeit aber könnte dir wenn ich zuhause bin was schicken. Ist eine Unit, von TThread abgeleitet, die einfache HTTP-Requests machen kann (content-length und chunked encoding werden unterstützt, allerdings keine Kompression, keep-alive etc, also recht minimalistisch). Aber ich denke, bis es soweit ist, hast du schon viele Beispiele von anderen Menschen bekommen.. :stupid:
Und Winsock = Winapi. Würd ich mal so sagen.

sirius 20. Okt 2009 08:42

Re: TCP Socket Programmierung möglichst ohne Komponenten
 
1. Die Vorstellung "ohne Komponenten"
Du willst ohne Komponenten, wie z.B. Indy arbeiten und versuchst dann eine Instanz von Tidhttp zu ertsellen? Wie passt das zusammen? --> Was willst du wirklich. Einfach nur keine Formulare (--> Konsolenanwendung) oder auch keine Komponenten wie Tidhttp oder TClientsocket etc. pp.

2. WinSock
WinSock ist die Unit, welche du in Delphi einbinden musst um nativ auf die WinAPI-Funktionen zur Socketprogrammierung zugriefen zu können (bzw. deren Deklarationen).

3. "ohne 'Extra-Unit' "
Was soll das heißen? Du kannst auch in einer Konsolenanwendung eine extra Unit anlegen um bestimmte Funktionen auszulagern / zu strukturieren. Du kannst auch eigene Klassen schreiben und verwenden ohne das Programm aufzublähen. --> Was stellst du dir genau vor?

hoika 20. Okt 2009 09:01

Re: TCP Socket Programmierung möglichst ohne Komponenten
 
Hallo,

Zitat:

Habe versucht IdHTTP ohne eigenes Formular zu nutzen. Es funktioniert zwar aber ich erhalte viele verschiedenartige Fehlermeldungen.
Also ohne Formular, nicht ohne Komponenten.

Zitat:

Und sobald ich den Eintrag "Forms" aus der uses-Klausel entferne funktioniert es logischerweise garnicht mehr.
Was funktioniert denn nicht ?


Es gibt hier ein Tutorial, die Indys in Turbo-Explorer zu benutzen.
(Ich finde es gerade nicht)

Man erzeugt die Komponente zur Laufzeit (TIndyCCC.Create(NIL))
und verknüpft dann die Events mit eigenen Prozeduren.


Heiko

chri_ri 20. Okt 2009 15:00

Re: TCP Socket Programmierung möglichst ohne Komponenten
 
Erstmal THX für die schnellen Antworten!^^

@eicht: minimalistisch klingt schonmal gut^^

Was ich eigentlich will:
Ein Programm, welches nur in der Lage ist HTTP_GET auszuführen um Daten zu laden und zu speichern und so klein wie möglich ist.
Deshalb möchte Ich möglichst unnötigen "Balast" wie z.B Forms vermeiden.

Tut mir leid, wenn ich mich etwas unklar ausgedrück habe.



mfg. chri_ri

Klaus01 20. Okt 2009 15:24

Re: TCP Socket Programmierung möglichst ohne Komponenten
 
Hallo,

wie schon gesagt Indy kannst Du auch ohne Form nutzen.
Was für Daten willst Du denn laden, vielleicht reicht Dir ja
auch ein Delphi-Referenz durchsuchenURLDownloadToFile.

Grüße
Klaus

shmia 20. Okt 2009 15:35

Re: TCP Socket Programmierung möglichst ohne Komponenten
 
Ich empfehle: http://www.delphipraxis.net/internal...t.php?t=112681

Der Titel TCP Socket Programmierung möglichst ohne Komponenten ist übrigens falsch.
Es geht ja nicht um TCP Socket Programmierung sondern darum, wie man ohne Delphi Komponenten einen HTTP GET-Request senden und empfangen kann.

hoika 20. Okt 2009 15:44

Re: TCP Socket Programmierung möglichst ohne Komponenten
 
Hallo,

Zitat:

Deshalb möchte Ich möglichst unnötigen "Balast"
Forms-Ballast vermeiden, OK.
Aber alles von Grund auf Neu-Erfinden, statt z.B. Indy zu verwenden ?


Heiko

sirius 20. Okt 2009 15:53

Re: TCP Socket Programmierung möglichst ohne Komponenten
 
Ich schmeiß hier mal folgendes rein, falls es jemand interessiert:
(Wie man sieht eine Konsolenanwendung)
Delphi-Quellcode:
program Project1;

//mit Konsole
{$APPTYPE CONSOLE}


uses
  activeX;


//Deklaration des Interfaces für den Zugriff auf XMLHttp-Klasse vom Internet Explorer (von Delphi generieren lassen)
//Ich habe mal die von mir benötigten Funktionen von safecall auf stdcall umgewandelt.
type
  IXMLHTTPRequest = interface(IDispatch)
    ['{ED8C108D-4349-11D2-91A4-00C04F7969E8}']
    function open(const bstrMethod: WideString; const bstrUrl: WideString; varAsync: OleVariant;
                   bstrUser: OleVariant; bstrPassword: OleVariant):HResult; stdcall;
    procedure setRequestHeader(const bstrHeader: WideString; const bstrValue: WideString); safecall;
    function getResponseHeader(const bstrHeader: WideString): WideString; safecall;
    function getAllResponseHeaders: WideString; safecall;
    function send(varBody: OleVariant):Hresult; stdcall;
    procedure abort; safecall;
    function Get_status: Integer; safecall;
    function Get_statusText: WideString; safecall;
    function Get_responseXML: IDispatch; safecall;
    function Get_responseText: WideString; safecall;
    function Get_responseBody: OleVariant; safecall;
    function Get_responseStream: OleVariant; safecall;
    function Get_readyState: Integer; safecall;
    procedure Set_onreadystatechange(const Param1: IDispatch); safecall;
    property status: Integer read Get_status;
    property statusText: WideString read Get_statusText;
    property responseXML: IDispatch read Get_responseXML;
    property responseText: WideString read Get_responseText;
    property responseBody: OleVariant read Get_responseBody;
    property responseStream: OleVariant read Get_responseStream;
    property readyState: Integer read Get_readyState;
    property onreadystatechange: IDispatch write Set_onreadystatechange;
  end;

//name der Klasse als Ressource (dadurch kann man vom IE auch auf Opera oder auf eins der restlichen UnterschichtBrowser umsteigen ;) )
resourcestring
 ClassName='Msxml2.XMLHTTP';


//hier Ersetzen, was mit der heruntergeladenen Seite passieren soll.
procedure DoSomething(text:Widestring);
begin
  writeln(text);
  readln;
end;

//Herunterladen mittels XMLHttpRequest
procedure Run;
var XMLHttpRequest:IXMLHttpRequest;
    ClassID:TGUID;
begin
  if CLSIDFromProgID(PWideChar(WideString(LoadResString(@ClassName))),ClassID) <> s_ok then
    writeln('Fehler bei CLSIDFromProgID')
  else
  begin
    if CoCreateInstance(ClassID,nil,CLSCTX_INPROC_SERVER,IXMLHttpRequest,XMLhttpRequest) <> s_ok then
      writeln('Fehler bei CoCreateInstance')
    else
    begin
      if XMLHttpRequest.open('Get','http://www.delphipraxis.net/',false,'','')<>s_ok then
        writeln('Fehler bei XMLHttpRequest.open')
      else
      begin
        if XMLHttpRequest.send(0)<>s_ok then
          writeln('Fehler bei XMLHttpRequest.send')
        else
        begin
          if XMLHttpRequest.readyState=4 then
            DoSomething(XMLHttpRequest.responseText)
          else
            writeln('Fehler beim Laden des Dokuments');
        end;
      end;
    end;
  end;
end;


//Programmstart
begin
  coinitialize(nil);
  Run;
  couninitialize;
end.
Edit: Soviel rote Kästen: da war doch tatsächlich jemand schneller...

chri_ri 20. Okt 2009 16:19

Re: TCP Socket Programmierung möglichst ohne Komponenten
 
Hey erstmal vielen Dank erstmal!^^

muss mir das erstmal alles in Ruhe anschauen.

werde mich sicherlich wieder melden.



mfg. chri_ri

chri_ri 20. Okt 2009 17:14

Re: TCP Socket (+ HTTP_GET) möglichst ohne Komponenten
 
@sirius:
Also der Code ist genau was ich gesucht habe.
Aber was müsste Ich tun, wenn Ich darüber auch binäre Daten anfordern, sprich eine Datei laden möchte?

Schonmal THX.


Kleiner Gedankeneinwurf (Ich weiß, da müsste ich eigentlich fast einen neuen Thread aufmachen):
Wie müsste Ich eigentlich einen HTTP_GET Request bzw. das Anfordern von binären Daten unter Linux realisieren?


@shmia:
Den Titel hatte Ich deshalb so gewählt, da Ich zuerst nach einer Möglichkeit gesucht hatte um überhaupt im Rahmen meiner Bedingungen einen kleinen TCP Client zu realisieren, um den HTTP_GET Request dann einfach nach dem Verbindungsaufbau mit z.B. "GET /index.php?... HTTP/1.1 ...." auszuführen.
Außerdem wäre ein kleiner TCP Client auch sehr praktisch gewesen, da ich auch eine einfacht TCP-Kommunikation (paar Befehle zwischen zwei Anwendungen über Netzwerk austauachen) für eine andere Anwendung suche.



mfg. chri_ri

sirius 20. Okt 2009 18:17

Re: TCP Socket (+ HTTP_GET) möglichst ohne Komponenten
 
Bei BinärenDaten liefert die Methode Responsetext einen Fehler. Jetzt musst du ResponseBody verwenden.
Dieses liefert dir ein eindimensionales varArray zurück, auf dessen Inhalt du dann folgendermaßen zugreifen kannst:
(Achtung du musst jetzt die Unit Variants einbinden, welche dein Programm gleich wieder ein schönes Stück größer macht)

Delphi-Quellcode:
var vArray:Variant;

//also anstatt Responsetext:
vArray:=XMLHttpRequest.responsebody;
Zugriff geht jetzt bspw. über vArray[0] bis vArray[x]. Die einzelnen Bytes kannst du jetzt in eine Datei speichern oder anzeigen, wenn du sie interpretieren kannst.
Von wo bis wo das Array im Index läuft bekommst du über die Funktionen varArrayLowBound(vArray,1) und VarArrayHighBound(...) heraus. Die eins steht für die erste Dimension (in diesem Fall ist nur eine zu erwarten)
Mit VarArrayLock bekommst du einen Zeiger auf die gesamten Daten, den man recht simpel speichern kann, das sähe folgendermaßen aus:
Delphi-Quellcode:
procedure SaveToFile(x:Variant);
var len:Integer;
    Data:Pointer;
    hFile:THandle;
    temp:Cardinal;
begin
  len:=VarArrayHighBound(x,1)-VarArrayLowBound(x,1);//Länge ermitteln
  Data:=VarArrayLock(x); //Pointer auf den ArrayInhalt bekommen
  try
    hfile:=CreateFile('D:\test.jpg',Generic_Write,0,nil,Create_Always,0,0); //Datei öffnen über WinAPI (ich habe als test ein JPG-Bild geladen)
    try
      Writefile(hfile,Data^,len,temp,nil); //Inhalt schreiben (Achtung! Derzeit keine Fehlerbehandlung)
    finally
      closehandle(hFile); //Datei schließen
    end;
  finally
    VarArrayUnlock(x); //Zugriff auf Array wieder freigeben
  end;
end;

Edit:
Um ohne den Comfort der Unit Variants auszukommen (EXE-Datei wird kleiner) geht obige Funktion auch so:
Delphi-Quellcode:
procedure SaveToFile(x:Variant);
var len:Integer;
    psa:PSafeArray;
    Data:Pointer;
    hFile:THandle;
    temp:Cardinal;
    UBound,LBound:Integer;
begin
  psa:=PSafeArray(TVarData(x).VArray);
  SafeArrayGetUBound(psa,1,UBound);
  SafeArrayGetLBound(psa,1,LBound);
  len:=UBound-LBound;
  SafeArrayAccessData(psa,Data);
  try
    hfile:=CreateFile('D:\test.jpg',Generic_Write,0,nil,Create_Always,0,0);
    try
      Writefile(hfile,Data^,len,temp,nil);
    finally
      closehandle(hFile);
    end;
  finally
    SafeArrayUnaccessData(psa);
  end;
end;
Edit2:
All das funktioniert nur, wenn auf dem Rechner der IE installiert ist (wovon man derzeit noch ausgehen kann). Aber andere Browser gehen eben mit der Änderung des Ressourcenstrings auch (sollten zumindest). Das liegt daran, dass diese Klasse die hier benutzt wird quasi standardisiert ist (den genauen Status kenne ich leider nicht). Und deshalb sind diese Funktionen wohl auch in Linux verfügbar. Wie man das aber dort macht, weiß ich nicht.

chri_ri 21. Okt 2009 14:01

Re: TCP Socket (+ HTTP_GET) möglichst ohne Komponenten
 
Mal wieder vielen Dank!^^

Muss das erstmal ausprobieren. Habe jetzt keine Zeit. Gebe später mein Feedback.

Werde das auch mal unter Linux (Debian 5.0.3 x86) ausprobieren^^



mfg. chri_ri


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:54 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz