AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Netzwerke Delphi ServerSocket/TcpServer als Webserver -> Schwierigkeiten
Thema durchsuchen
Ansicht
Themen-Optionen

ServerSocket/TcpServer als Webserver -> Schwierigkeiten

Ein Thema von Darkface · begonnen am 22. Nov 2009 · letzter Beitrag vom 19. Feb 2010
Antwort Antwort
Seite 1 von 2  1 2      
Darkface

Registriert seit: 18. Apr 2008
89 Beiträge
 
Delphi XE Professional
 
#1

ServerSocket/TcpServer als Webserver -> Schwierigkeiten

  Alt 22. Nov 2009, 09:23
Hiho DP'ler,

Ich habe vor einen kleinen Webserver zu schreiben der einfach auf Anfrage eines Browsers eine sich ständig ändernde Webseite ausgibt.

Ich dachte mir also ich nehme mir die ServerSocket Komponente oder alternativ die TcpServer Komponente und reagiere einfach immer wenn ein Browser eine Anfrage sendet damit drauf das ich dem Browser simpel mit SendText den Quellcode der Seite rüberschiebe.

Das funktioniert aber mit beiden Komponenten nur halb.

Delphi-Quellcode:
procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var i:Integer;
begin
    s:=Socket.ReceiveText;
    Memo1.Lines.Add(s);
    For i:=0 to ServerSocket1.Socket.ActiveConnections -1 do begin
        ServerSocket1.Socket.Connections[i].SendText('<html><head><meta http-equiv="refresh" content="1; URL=/"></head><body>It Works? Or?
        +IntToStr(Random(10000)) +'</body></html>');
        //ServerSocket1.Active:=False;
        //ServerSocket1.Active:=True;
    end;
end;
Das war der sehr unsaubere Code um auf die Anfrage des Browsers mittels ServerSocket zu reagieren. Wie ihr sehr es soll nicht schön sein sondern einfach nur funktionieren . Problem dabei, der Browser würde unendlich lang die Webseite laden wenn ich nicht mittels ServerSocket1.Active die Verbindung kurz unterbrechen würde. Wenn ich das tue wird die Webseite dann auch Problemlos im Browser angezeigt. Das ist aber selbst mir zu unsauber - sobald mehrere Leute versuchen die Seite aufzurufen bekomme ich Probleme, da fliegen mir teils Exceptions um die Ohren und die Browser zeigen immerwieder an das die Verbindung abgebrochen/zurückgesetzt ect. ist.

Beim TcpServer habe ich es ähnlich versucht...
- empfangen der Browser Anfrage
- die in Memofeld schreiben
- *Browser das Stückchen rohes Fleisch hinwerf* (Per SendText den Quellcode rübersenden)

Also imprinzip wie oben. Problem ist hier das der Browser nur bei jedem 5ten Versuch die Webseite anzeigt - dann auch korrekt. Bei den anderen 4 Versuchen kommt ein "Verbindung zurückgesetzt". Beim TcpServer habe ich übrigens nicht das Problem mit dem "unendlichen Laden" der Seite, wenn die Seite angezeigt wird dann richtig.

Wie bekomme ich das ganze also zuverlässiger hin? Wo hängts? Weis da jemand Rat
Alexander
Ich halte Ordnung.
Zum Beispiel mein Schreibtisch: Hier ist alles zeitlich geordnet - was zuletzt kam, liegt oben. (Frank Erhoff)
  Mit Zitat antworten Zitat
Benutzerbild von sirius
sirius

Registriert seit: 3. Jan 2007
Ort: Dresden
3.443 Beiträge
 
Delphi 7 Enterprise
 
#2

Re: ServerSocket/TcpServer als Webserver -> Schwierigkeit

  Alt 22. Nov 2009, 09:37
Ich kenne micht mit http nicht so aus, aber willst du nicht wenigstens einen http-Header mitschicken?

Edit: Und ob die Verbindung geschlossen werden muss, steht doch in der Anfrage drin, oder?
Dieser Beitrag ist für Jugendliche unter 18 Jahren nicht geeignet.
  Mit Zitat antworten Zitat
Darkface

Registriert seit: 18. Apr 2008
89 Beiträge
 
Delphi XE Professional
 
#3

Re: ServerSocket/TcpServer als Webserver -> Schwierigkeit

  Alt 22. Nov 2009, 09:43
Wenn dadurch mein Problem nicht hervorgerufen wird dann eigentlich nicht. Ich bekomme ja (zwar unzuverlässig aber es geht) den Quelltext den ich an den Browser zurücksende angezeigt. Nur halt mit oben genannten Problemen. Würde ein Header das lösen?

Ich kenne mich mit dem Protokoll leider auch nicht aus und hatte gehofft das es reicht dem Browser einfach Text zurückzusenden und er sich damit zufrieden gibt. Das wiegesagt klappt ja auch (teilweise) ^^.

Edit: Danke für die schnelle Antwort ^^.
Alexander
Ich halte Ordnung.
Zum Beispiel mein Schreibtisch: Hier ist alles zeitlich geordnet - was zuletzt kam, liegt oben. (Frank Erhoff)
  Mit Zitat antworten Zitat
Benutzerbild von sirius
sirius

Registriert seit: 3. Jan 2007
Ort: Dresden
3.443 Beiträge
 
Delphi 7 Enterprise
 
#4

Re: ServerSocket/TcpServer als Webserver -> Schwierigkeit

  Alt 22. Nov 2009, 09:49
Egel ob http oder ein anderes Anwendungsprotokoll: Ein Header ist insofern wichtig, als dass er mindestens die Größe/Länge des Inhalts angibt. Ohne diese Angabe ist es dem Empfänger unmöglich, das Gesendete korrekt zusammenzusetzen. TCP/IP kann diese Funktionalität nicht liefern. Es zerhackt dir deinen Text in mehrere Pakete und irgendiwe muss der Empfänger ja wissen, wie lange er noch warten muss.
==> Mindestens eine Längenangabe o.ä#. muss in so ein Anwendungsprotokoll. Und http hat das IMHO auch enthalten. Sollte man auch dringend nutzen.
Und evtl. gibt es noch andere wichtige Angaben im Header, keine Ahnung.
Dieser Beitrag ist für Jugendliche unter 18 Jahren nicht geeignet.
  Mit Zitat antworten Zitat
Darkface

Registriert seit: 18. Apr 2008
89 Beiträge
 
Delphi XE Professional
 
#5

Re: ServerSocket/TcpServer als Webserver -> Schwierigkeit

  Alt 22. Nov 2009, 11:36
Und wie sieht so ein Http Header in Delphi aus? Send ich das einfach als Text vorne weg oder wie funktioniert das? Hab mir so ein Http Header grad mal angesehen, da kommt so eine Längenangabe in Byte vor, aber wie kann ich die Angeben wo ich doch nur Texte (SendText) und keine Dateien mit festen Dateigrößen in Streams versende?
Alexander
Ich halte Ordnung.
Zum Beispiel mein Schreibtisch: Hier ist alles zeitlich geordnet - was zuletzt kam, liegt oben. (Frank Erhoff)
  Mit Zitat antworten Zitat
Benutzerbild von thkerkmann
thkerkmann

Registriert seit: 7. Jan 2006
Ort: Pulheim Brauweiler
464 Beiträge
 
Delphi 2010 Professional
 
#6

Re: ServerSocket/TcpServer als Webserver -> Schwierigkeit

  Alt 22. Nov 2009, 11:43
Hi,

schau mal in den Demos nach, da gibt es einen HTTPserver als Beispiel.

Ausserdem solltest Du die Antwort an den "Socket" = TCustomWinSocket zurückschicken, und diesen schliessen. Das wäre die richtige Vorgehensweise.

Gruss
Thomas Kerkmann
Ich hab noch einen Koffer in Borland.
http://thomaskerkmann.wordpress.com/
  Mit Zitat antworten Zitat
Benutzerbild von DataCool
DataCool

Registriert seit: 10. Feb 2003
Ort: Lingen
909 Beiträge
 
Delphi 10.3 Rio
 
#7

Re: ServerSocket/TcpServer als Webserver -> Schwierigkeit

  Alt 22. Nov 2009, 11:51
Hi Darkface,

nimm doch den IdHttpServer(Indy-Komponenten) der regelt für Dich alles.
Du must nur auf die Events:

- OnCommandGet und
- OnCommandOther

entsprechend die Antwortvariablen füllen, das war.

Greetz Data
Der Horizont vieler Menschen ist ein Kreis mit Radius Null, und das nennen sie ihren Standpunkt.
  Mit Zitat antworten Zitat
Benutzerbild von sirius
sirius

Registriert seit: 3. Jan 2007
Ort: Dresden
3.443 Beiträge
 
Delphi 7 Enterprise
 
#8

Re: ServerSocket/TcpServer als Webserver -> Schwierigkeit

  Alt 22. Nov 2009, 12:32
Zitat von Darkface:
Und wie sieht so ein Http Header in Delphi aus? Send ich das einfach als Text vorne weg ...
Genau.
Delphi-Quellcode:
//mit meinen bescheidenen http-Kentnissen:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, scktcomp, StdCtrls;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    procedure FormCreate(Sender: TObject);
  private
    { Private-Deklarationen }
    FServer:TServersocket;
    FIndex:Integer;
  public
    { Public-Deklarationen }
    procedure ClientConnect(Sender:TObject; Socket: TCustomWinSocket);
    procedure ClientDisconnect(Sender:TObject; Socket: TCustomWinSocket);
    procedure ClientRead(Sender:TObject; Socket: TCustomWinSocket);
    procedure ClientWrite(Sender:TObject; Socket: TCustomWinSocket);
    procedure ClientError(Sender:TObject; Socket: TCustomWinSocket;
                 ErrorEvent: TErrorEvent; var ErrorCode: Integer);
  end;

  TClientData=class
    Constructor Create;
    Destructor Destroy; override;
   private
    FCanWrite: boolean; //ist socket bereit zum senden
    FIndex: Integer; //laufender Index
    FSocket: TCustomWinSocket; //Parent Socket merken, für die Antwort
    FReceivedText:TStringList; //Stringlist wegen zu erwartenden http-Header
    procedure SetCanWrite(const Value: boolean);
    procedure SetIndex(const Value: Integer);
    procedure SetSocket(const Value: TCustomWinSocket);
   protected
    procedure SendNotImpl;
    procedure SendOK(const content:String);
   public
    property CanWrite:boolean read FCanWrite write SetCanWrite;
    property Index:Integer read FIndex write SetIndex;
    property Socket:TCustomWinSocket read FSocket write SetSocket;
    procedure Receive(const Text:string);

  end;


var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.ClientConnect(Sender: TObject; Socket: TCustomWinSocket);
var ClientData:TClientData;
begin
  ClientData:=TClientData.Create;
  ClientData.CanWrite:=false;
  inc(FIndex);
  ClientData.Index:=FIndex;
  ClientData.Socket:=Socket;
  Socket.Data:=ClientData;
  memo1.lines.add(format('%d connected',[ClientData.Index]));
end;

procedure TForm1.ClientDisconnect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  assert(TObject(Socket.Data) is TClientData);
  memo1.lines.add(format('%d disconnected',[TClientData(Socket.Data).Index]));
  TObject(Socket.Data).Free;
end;

procedure TForm1.ClientError(Sender: TObject; Socket: TCustomWinSocket;
  ErrorEvent: TErrorEvent; var ErrorCode: Integer);
var s:String;
begin
  assert(TObject(Socket.Data) is TClientData);
  case ErrorEvent of
    eeGeneral: s:='General';
    eeSend: s:='Send';
    eeReceive: s:='Receive';
    eeConnect: s:='Connect';
    eeDisconnect: s:='Disconnect';
    eeAccept: s:='Accept';
    eeLookup: s:='Lookup';
    else s:='Empty';
  end;
  memo1.Lines.Add(format('%d: Error on %s',[TClientData(Socket.Data).index,s]));
  ErrorCode:=0;
end;

procedure TForm1.ClientRead(Sender: TObject; Socket: TCustomWinSocket);
var s:string;
begin
  assert(TObject(Socket.Data) is TClientData);
  s:=Socket.ReceiveText;
  memo1.lines.add(format('%d Read: %s',[TClientData(Socket.Data).index,s]));
  TClientData(Socket.Data).Receive(s);
end;

procedure TForm1.ClientWrite(Sender: TObject; Socket: TCustomWinSocket);
begin
  assert(TObject(Socket.Data) is TClientData);
  memo1.lines.add(format('%d: CanWrite',[TClientData(Socket.Data).index]));
  TClientData(Socket.Data).CanWrite:=true;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FServer:=TServersocket.Create(self);
  FServer.Port:=80;
  FServer.Service:='';
  FServer.ServerType:=stNonBlocking;
  FServer.OnClientConnect:=ClientConnect;
  FServer.OnClientDisconnect:=ClientDisconnect;
  FServer.OnClientWrite:=ClientWrite;
  FServer.OnClientRead:=ClientRead;
  FServer.OnClientError:=ClientError;
  FServer.Open;
  FIndex:=0;
end;


{ TClientData }

constructor TClientData.Create;
begin
  FReceivedText:=TstringList.Create;
end;

destructor TClientData.Destroy;
begin
  FReceivedText.Free;
end;

//neu erhaltenen TExt speichern und überprüfen ob breits eine Leerzeile vorhanden ist
//Leerzeile == Ende HTTP-Anfrage
procedure TClientData.Receive(const Text: string);
var i:Integer;
    Endpos:Integer;
    s:String;
    Req:String;
begin
  FReceivedTExt.Text:=FReceivedTExt.Text+Text;
  while FReceivedTExt.count>0 do
  begin
    EndPos:=-1;
    for i:=0 to FReceivedTExt.count-1 do
    begin
      if FReceivedText.Strings[i]='then //auf http-Header Ende warten/suchen
      begin
        EndPos:=i; //Leerzeile gefunden
        break;
      end;
    end;

    if Endpos>0 then //wenn leerzeile und noch etwas mehr gefunden
    begin
      //eigentlich hier noch auf CanWrite überprüfen, ansonsten iust unser socket noch nicht fertig
      s:=FReceivedText.Strings[0];
      if Copy(s,1,4)='GET then //erste Zeile auseinanderbauen
      begin
        Delete(s,1,4);
        i:=pos(' ',s);

        Req:=copy(s,1,i-1);
        Delete(s,1,i);

        if copy(s,1,5)='HTTP/then
        begin
          //antworten (eigentlich müsste man noch den Rest des Headers analysieren)
          SendOK(req);
        end else
          SendNotImpl;
      end else
        SendNotImpl;
    end;

    for i:=0 to Endpos do FReceivedText.Delete(0); //alles Bearbeitete löschen
  end;
end;

//"Fehler" senden
procedure TClientData.SendNotImpl;
begin
  FSocket.SendText('HTTP/1.1 501 Not Implemented'#13#10#13#10);
end;

//Antwort senden
procedure TClientData.SendOK(const Content:String);
var Ans:TStringList;
    HTML:String;
begin
  ans:=TStringList.Create;
  try
    HTML:='<html><head><meta http-equiv="refresh" content="1; URL=/"></head><body>It Works? Or? '
        +inttostr(FIndex) +'
'+Content+'</body></html>'#13#10;

    ans.Add('HTTP/1.1 200 OK');
    ans.add('Server: myDelphi');
    ans.add('Content-Length: '+inttostr(length(HTML)));
    ans.add('Content-Language: de');
    ans.add('Content-Type: text/html');
    ans.add('Connection: close');
    FSocket.SendText(Ans.Text+#13#10+HTML);

  finally
    ans.free;
  end;
end;

procedure TClientData.SetCanWrite(const Value: boolean);
begin
  FCanWrite := Value;
end;

procedure TClientData.SetIndex(const Value: Integer);
begin
  FIndex := Value;
end;

procedure TClientData.SetSocket(const Value: TCustomWinSocket);
begin
  FSocket := Value;
end;

end.
Edit: @Datacool: Ich vermute der TE möchte das Prinzip hinter einem http-Server verstehen. Da hilft keine fertige Komponente.
Dieser Beitrag ist für Jugendliche unter 18 Jahren nicht geeignet.
  Mit Zitat antworten Zitat
Darkface

Registriert seit: 18. Apr 2008
89 Beiträge
 
Delphi XE Professional
 
#9

Re: ServerSocket/TcpServer als Webserver -> Schwierigkeit

  Alt 22. Nov 2009, 12:33
Zitat von thkerkmann:
[...]
in den Demos nach, da gibt es einen HTTPserver als Beispiel
[...]
die Antwort an den "Socket" = TCustomWinSocket zurückschicken, und diesen schliessen
[...]
Habe die Demos gerade durchsucht dort aber nur ein Indy Server Beispiel gefunden. Und Indy hab ich mit meinem Turbo Delphi noch nie zum laufen gebracht was dann auch den Vorschlag von DataCool zunichte macht. Eigentlich auch unnötig wenn ich diese kleine unstabilität aus dem Tcp/Server Socket rausbekommen könnte. Wie meinst du das mit der Antwort an den Socket zurückschicken um ihn zu schließen?

Danke für eure schnelle Hilfe...
Darkface

EDIT: Ach sirius danke für deinen Code ich habs grad erst gesehen, ich werde mich zeitnah damit beschäftigen!
Alexander
Ich halte Ordnung.
Zum Beispiel mein Schreibtisch: Hier ist alles zeitlich geordnet - was zuletzt kam, liegt oben. (Frank Erhoff)
  Mit Zitat antworten Zitat
Darkface

Registriert seit: 18. Apr 2008
89 Beiträge
 
Delphi XE Professional
 
#10

Re: ServerSocket/TcpServer als Webserver -> Schwierigkeit

  Alt 23. Nov 2009, 16:52
Total genial sirius, vielen Dank für deine Hilfe!
Hab mit deinem Code den mini Webserver umgebaut und es hat wunderbar hingehauen!


MfG
Darkface
Alexander
Ich halte Ordnung.
Zum Beispiel mein Schreibtisch: Hier ist alles zeitlich geordnet - was zuletzt kam, liegt oben. (Frank Erhoff)
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:38 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz