[dephi] file transfers niet over het netwerk wel lokaal

Pagina: 1
Acties:
  • 113 views sinds 30-01-2008
  • Reageer

  • THIJZEL
  • Registratie: Januari 2001
  • Niet online
Hallo,

Ik heb 2 componentjes geschreven, één client(TTransferclient) en een server(TTransferserver), deze zijn bedoelt om files te transferen over het netwerk, ze zijn gebaseerd op Tclientsocket en Tserversocket..

Dit heb ik getest en ze werken goed, zo lang het lokaal blijft...

zodra ik files over het netwerk ga zenden gaat het fout, dan stopt hij ineens op een onwillekeurig punt ( wel een veelvoud an 8kb, omdat hij de data in stukken van 8kb stuurd..)

ik kom er niet meer uit, zou iemand misschien weten waar het aan zou kunnen liggen:

source:
(sorry voor de vele code..)

ttransferclient
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
unit transferclient;

interface

uses
  Windows, Messages, SysUtils, Classes, ScktComp,dialogs,ExtCtrls;

type
  Ttransferclient = class(tclientsocket)
  private
    function getfilename:string;
    procedure setfilename(value:string);
    function getsendpercentage:integer;
    procedure sendnext;
    procedure init;

    //var  bestandstream: tfilestream;
    { Private declarations }
  protected
    FOnTransfercomplete: TNotifyEvent;

    procedure Event(Socket: TCustomWinSocket; SocketEvent: TSocketEvent);override;
    { Protected declarations }
  public
    procedure sendbegin;
    property sourcefile:string read getfilename write setfilename;
    property sendpercentage:integer read getsendpercentage;
    constructor Create(AOwner: TComponent); override;
    { Public declarations }
  published
    property OnTransfercomplete: TNotifyEvent read FOnTransfercomplete Write FOnTransfercomplete;
    { Published declarations }
  end;

var bestandsnaam:string;
bestandstream: tfilestream;
buffercount:integer;
timeouttimer:ttimer;

procedure Register;


implementation

procedure Register;
begin
  RegisterComponents('Samples', [Ttransferclient]);
end;

function Ttransferclient.getfilename:string;
begin
        result:=bestandsnaam;
end;

procedure Ttransferclient.setfilename(value:string);
begin
        bestandsnaam:=value;
end;

constructor Ttransferclient.Create(AOwner: TComponent);
begin
        inherited create(AOwner);
end;

procedure Ttransferclient.sendbegin;
const
 MaxChunkSize = 8192;
var
 filesize:integer;
begin
        if Socket.Connected = true then
        begin
                bestandstream:=tfilestream.Create(sourcefile,fmOpenRead);
                bestandstream.Position := 0;
                //zend eerst de size van het bestand
                filesize:=bestandstream.Size;
                socket.SendBuf(filesize,sizeof(filesize));
        end;


end;

procedure Ttransferclient.sendnext;
const
 MaxChunkSize = 8192;
var
 ChunkSize: Integer;
 CopyBuffer: array[0..MaxChunkSize] of Byte;
begin
        if Socket.Connected = true then
        begin
                if (bestandstream= nil) then bestandstream:=tfilestream.Create(sourcefile,fmOpenRead);

                 ChunkSize := bestandstream.Size - bestandstream.Position;
                 if ChunkSize > 0 then
                 begin
                        if ChunkSize > MaxChunkSize then ChunkSize:= MaxChunkSize;
                        bestandstream.Read(CopyBuffer, ChunkSize);
                        Socket.SendBuf(CopyBuffer, ChunkSize);
                        //ChunkSize := bestandstream.Size - bestandstream.Position;
                        buffercount:=buffercount+1;
                        if bestandstream.Position = bestandstream.Size then init;
                 end
         end
end;

procedure Ttransferclient.Event(Socket: TCustomWinSocket; SocketEvent: TSocketEvent);
begin
  case SocketEvent of
    seRead: if (socket.ReceiveText= 'next') then
    begin

     sendnext;
    end;
    else begin
      inherited Event(Socket,SocketEvent);
    end;
  end;
end;


function ttransferclient.getsendpercentage:integer;
var deler:integer;
begin
     try
        if (bestandstream.Size > 0) then
        begin
                deler := bestandstream.size div 100;
                result := bestandstream.Position div deler;
        end;
     except
        result:=100;
     end;
end;

procedure ttransferclient.init;
begin
        if Assigned(FOnTransfercomplete) then FOnTransfercomplete(Self);
        bestandstream.Free;
        bestandstream:=nil;
        self.Active:=false;

end;

end.


ttransferserver:
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
unit TransferServer;

interface

uses
  Windows, Messages, SysUtils, Classes, ScktComp,dialogs;

type
  TTransferServer = class(tserverSocket)
  private
    function getdestfile:string;
    procedure setdestfile(Value: string);
    { Private declarations }
  protected
    FOnTransfercomplete: TNotifyEvent;
    { Protected declarations }
  public
    constructor Create(AOwner: TComponent); override;
    Procedure Clientread(Sender: TObject;
  Socket: TCustomWinSocket);
    { Public declarations }
  published
    property destfile: string  read getdestfile write setdestfile;
    property OnTransfercomplete: TNotifyEvent read FOnTransfercomplete Write FOnTransfercomplete;
    { Published declarations }
  end;

procedure Register;

var bestandsnaam :string;
    bestandsnaamstr: tfilestream;
    sizebekend:boolean;
    grootte:integer;

implementation

procedure Register;
begin
  RegisterComponents('Samples', [TTransferServer]);
end;

constructor ttransferserver.Create(AOwner: TComponent);
begin
        inherited create(AOwner);
        socket.OnClientRead := clientread;
        sizebekend:=false;
        bestandsnaamstr :=nil;
end;

Procedure ttransferserver.Clientread(Sender: TObject; Socket: TCustomWinSocket);
const
 MaxChunkSize = 8192;
var
 BytesReceived: Longint;
 CopyBuffer: Array[0..MaxChunkSize] of Byte;
 ChunkSize: Integer;
begin

        if sizebekend = false then
        begin
                        ChunkSize:= Socket.ReceiveLength;
                        if ChunkSize > MaxChunkSize then ChunkSize:= MaxChunkSize;
                        socket.ReceiveBuf(grootte,ChunkSize);
                        sizebekend:=true;

        end
        else
        Begin
                if not FileExists(bestandsnaam) then
                begin
                        //als de file niet bestaat maak hem dan en close de handle
                        fileclose(FileCreate(bestandsnaam));
                end
                else
                begin
                        //als hij al wel bestaat, delete hem dan en maak een nieuwe aan
                        deletefile(bestandsnaam);
                        fileclose(FileCreate(bestandsnaam));

                end;

                if  bestandsnaamstr = nil  then
                begin
                        {als de stream nog niet bestaat, creer hem dan}
                        bestandsnaamstr := tfilestream.Create(bestandsnaam,fmOpenReadWrite);
                        bestandsnaamstr.position:=0;
                end;

                {lees de received bytes en schrijf deze naar te stream, lees ze per MAXCHUNKSIZE}
                while (Socket.ReceiveLength > 0) do
                begin
                        ChunkSize:= Socket.ReceiveLength;

                        if ChunkSize > MaxChunkSize then ChunkSize:= MaxChunkSize;
                        BytesReceived:= Socket.ReceiveBuf(CopyBuffer,ChunkSize);
                        bestandsnaamstr.Write(CopyBuffer, BytesReceived);
                end;
         end;
         {zend de volgende 8 bytes, nog ff wat netter coden...............}
         if assigned(bestandsnaamstr) then
         begin
                if bestandsnaamstr.Position < grootte then
                begin
                        socket.SendText('next');
                end
                else
                begin
                        if Assigned(FOnTransfercomplete) then FOnTransfercomplete(Self);
                        bestandsnaamstr.Free;
                end;
         end
         else
         begin
             socket.SendText('next')
         end;


end;

function ttransferserver.getdestfile:string;
begin
        result:=bestandsnaam;
end;

procedure ttransferserver.setdestfile(Value: string);
begin
        bestandsnaam:=Value;
end;

end.

  • THIJZEL
  • Registratie: Januari 2001
  • Niet online
Het stomme is dat het probleem zich niet voordoet tijdens het debuggen, maar zodra ik de breakpoints er af haal, dan stop de transfer vrijwel meteen...

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 00:45

Creepy

Tactical Espionage Splatterer

THIJZEL schreef op 28 May 2003 @ 13:59:
Het stomme is dat het probleem zich niet voordoet tijdens het debuggen, maar zodra ik de breakpoints er af haal, dan stop de transfer vrijwel meteen...
En waar in de code stopt het programma? Krijg je daar nog een melding bij?

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 01:25

Tomatoman

Fulltime prutser

Zet MaxChunkSize eens op 1024.

Een goede grap mag vrienden kosten.


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

Loggen?

* curry684 vraagt zich af of mensen nog wel leren debuggen tegenwoordig...

Professionele website nodig?


  • THIJZEL
  • Registratie: Januari 2001
  • Niet online
ik heb het al gevonden, nouja.. ik heb het verholpen.
Als ik een sleep zet van 2ms in ttransferserver net voordat hij next stuurt, dan werkt het wel.( niet een erg nette oplossing.. :P)
Het lijkt alsof de transferclient niet snel genoeg kan initialiseren ofzo..

  • alienfruit
  • Registratie: Maart 2003
  • Laatst online: 22-08 17:28

alienfruit

the alien you never expected

curr684, loggen heeft alleen zin als je CodeSite gebruikt :D
(sorry moest effe)

Overigens zou ik nooi een sleep gebruiken, is als eerste niet netjes en is niet echt precies. imho.

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 00:45

Creepy

Tactical Espionage Splatterer

alienfruit schreef op 28 May 2003 @ 14:34:
curr684, loggen heeft alleen zin als je CodeSite gebruikt :D
(sorry moest effe)
* Creepy mist de link tussen CodeSite en het genereren van logs...
(sorry.. moest ook effe ;) ).

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


  • Reptile209
  • Registratie: Juni 2001
  • Laatst online: 02:19

Reptile209

- gers -

Zomaar ff wat losse invallen:

* Hoe staat je ClientType (property van TClientSocket): clNonBlocking (default) of clBlocking? En als je dat omwisselt?

* Het feit dat 'ie wel loopt met breakpoints en/of sleep() lijkt er op te wijzen dat je applicatie te weinig tijd krijgt. Voeg bovenin Client.SendNext eens een Application.ProcessMessages toe, en eventueel ook eentje vlak voor het versturen van 'next' in de server.

* Of het gaat ergens mis in een time-out instelling wat pas optreedt over het inet en niet op je LAN. Kweenie, maar heeft een socket nog time-out instellingen?

Mijn centjes dus...

offtopic:
w00t! 1000e post! Wees vereerd! :P

Zo scherp als een voetbal!


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

* curry684 mist ook enorm de link tussen CodeSite en het onverbeterbare nut van logs bij debugging....

Professionele website nodig?


  • THIJZEL
  • Registratie: Januari 2001
  • Niet online
Reptile209 schreef op 28 mei 2003 @ 14:46:
Zomaar ff wat losse invallen:

* Hoe staat je ClientType (property van TClientSocket): clNonBlocking (default) of clBlocking? En als je dat omwisselt?

* Het feit dat 'ie wel loopt met breakpoints en/of sleep() lijkt er op te wijzen dat je applicatie te weinig tijd krijgt. Voeg bovenin Client.SendNext eens een Application.ProcessMessages toe, en eventueel ook eentje vlak voor het versturen van 'next' in de server.

* Of het gaat ergens mis in een time-out instelling wat pas optreedt over het inet en niet op je LAN. Kweenie, maar heeft een socket nog time-out instellingen?

Mijn centjes dus...

offtopic:
w00t! 1000e post! Wees vereerd! :P
ff een late reactie maar ik was een paar daagjes weg 8)

de stockets staan gewoon standaard op stnonblocking..

ik kan application niet aanroepen vanuit mijn component,
is er niet iets als : 'owner as application' ?
(een oplossing zou zijn om bijvoorbeeld een onsendnext event te bouwen, maar dat is niet netjes, het zou beteken dat de component zo 'los' niet goed zou werken..

tclientsocket en tserversocket hebben zover ik weet geen timeoutinstellingen..

[ Voor 11% gewijzigd door THIJZEL op 03-06-2003 14:16 ]


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

ik kan application niet aanroepen vanuit mijn component,
De application variabele is gewoon een global en dus altijd beschikbaar. Gewoon aanroepen dus.

Professionele website nodig?


  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 00:45

Creepy

Tactical Espionage Splatterer

curry684 schreef op 03 June 2003 @ 14:54:
[...]

De application variabele is gewoon een global en dus altijd beschikbaar. Gewoon aanroepen dus.
Niet vergeten de forms unit te includen ;)

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

offtopic:
Ik is uit de C++Builder school en forms.hpp gaat automagisch mee met de #include <vcl.h> die je altijd doet ;)

Professionele website nodig?


  • killermar
  • Registratie: Augustus 2002
  • Laatst online: 12-07 08:05
Heb je gegeken naar de help over TCustomWinSocket.SendBuf? Daar staat in wanneer je die sleep zou moeten doen...

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 00:45

Creepy

Tactical Espionage Splatterer

curry684 schreef op 03 June 2003 @ 16:04:
offtopic:
Ik is uit de C++Builder school en forms.hpp gaat automagisch mee met de #include <vcl.h> die je altijd doet ;)
Scheelt ;)
Maar de T.S include zowel vcl.pas als forms.pas niet, dus vandaar dat ik het ff melde :)

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


  • THIJZEL
  • Registratie: Januari 2001
  • Niet online
hmz, die processmessages hebben ook niet geholpen, ik zit te denken om mijn comonenten om te bouwen en te baseren op de sockets van de indy component suite.

  • BoomSmurf
  • Registratie: Maart 2003
  • Laatst online: 28-05 11:50

BoomSmurf

Am-Ende!

Naar Indy omzetten idd, of anders ICS, maar for gods sake geen TClient/TServerSocket...

(nb, met TIdTFTP server en client ben je klaar :))

  • killermar
  • Registratie: Augustus 2002
  • Laatst online: 12-07 08:05
Ook met Indy zal je maken krijgen met buffers die je niet in 1 keer van verzenden (tenzij je zoals boomsmurf zegt met TIdFTP aan de slag gaat). Overstappen zal m.i. jouw probleem niet oplossen. Controleren wat het socket-component daadwerkelijk heeft verzonden na hem opdracht daartoe gegeven te hebben weer wel denk ik.

  • martijn_brinkers
  • Registratie: November 2001
  • Laatst online: 31-10-2025
Ik kan je niet 123 een aanwijzing geven waarmee je code betrouwbaar werkt. Dit is omdat je code aan een boel kanten 'rammelt'. Je gebruikt non-blocking sockets op een blocking manier. Sockets in non-blocking mode wordt bijna altijd gebruikt in een single threaded applicatie. Je moet je dan wel houden aan de regels die bij non-blocking gelden omdat je anders de main thread blocked en er dus verder niks meer kan gebeuren. non-blocking sockets worden gewoonlijk 'bestuurd' mbv events waarbij dus windows je verteld wanneer er weer iets verzonden mag worden en wanneer er iets ontvangen is.

In je code gebruik je oa SendBuf maar je controleerd niet of deze alles heeft verstuurd. Uit de documentatie van sendBuf blijkt nl dat dat niet het geval hoeft te zijn:
If the WinSock internal buffer space is not able to accept the buffer being sent, SendBuf returns -1 and no data is queued at all. In this case, wait a bit for the WinSock to have a chance to send out already-queued data; then try again.
Een ander probleem is dat je er vanuit gaat dat data in duidelijk afgeschermde pakketjes wordt verstuurd. Dat is dus bij TCP niet zo! (UDP wel maar dat heeft zo zn eigen problemen).

Delphi:
1
seRead: if (socket.ReceiveText= 'next') then


Het kan dus gebeuren dat je eerst 'nex' ontvangt en later pas 't'. In jouw code zal zich dat niet snel voor doen maar het zou kunnen (denk bijv. aan nagle optie)

Gebruik van blocking sockets (zoals Indy) kan makkelijker zijn maar je zal dan wel gebruik moeten maken van threads (of van IdAntiFreeze maar dat raad ik niet aan) en dat heeft ook weer zn eigen 'problemen'.

  • THIJZEL
  • Registratie: Januari 2001
  • Niet online
BoomSmurf schreef op 03 June 2003 @ 23:28:
Naar Indy omzetten idd, of anders ICS, maar for gods sake geen TClient/TServerSocket...

(nb, met TIdTFTP server en client ben je klaar :))
nou, zo makkelijk zijn die ook niet, daar moet je ook nog een heleboel aan proggen.

ik probeer een component te maken die je met 2 commando's een file kan verzenden, en waarbij ik dus geen filestreams meer hoef te maken..

  • THIJZEL
  • Registratie: Januari 2001
  • Niet online
om toch maar weer terug te gaan naar mijn component, ik denk dat het idd aan de buffers in winsock ligt, is er een manier om uit te lezen of alles verzonden is en of deze dus leeg zijn?

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

Met de WSAIoctl functie met code SIO_FLUSH kun je alle huidige buffers flushen. Overigens ben ik nog steeds erg verbaasd als het nodig zou zijn.

Professionele website nodig?


  • THIJZEL
  • Registratie: Januari 2001
  • Niet online
curry684 schreef op 04 juni 2003 @ 14:44:
Met de WSAIoctl functie met code SIO_FLUSH kun je alle huidige buffers flushen. Overigens ben ik nog steeds erg verbaasd als het nodig zou zijn.
ik wil de buffers ook niet flushen, ik wil alleen maar controleren of ze leeg zijn..

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

Kunt alleen read-buffers opvragen, writebuffers niet. De reden dat ik je de 'flush'-functie aanwees is dat het een redelijk waterdichte methode is om je buffers leeg te krijgen waardoor je ze niet meer hoeft te controleren :)

Professionele website nodig?


  • THIJZEL
  • Registratie: Januari 2001
  • Niet online
ik geef het op, weet er iemand een andere goede manier van file transfers in delphi?

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

Ik heb voor het eerst eens vluchtig door je code geneust maar nogal wiedes dat het ding er mee uitscheidt: je leest doorlopend uit non-blocking sockets en gebruikt 0 bytes read als terminating condition! Daar het hele concept van non-blocking sockets is gebaseerd op dat calls niet blocken valt de Read direct terug met 0 bytes read als er (nog) geen data beschikbaar is, wat al snel het geval is bij remote transfers waarbij de bottleneck de netwerkverbinding is en niet de lezende/schrijvende CPU's. (...to be continued)

Professionele website nodig?


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

Je grootste fout zit 'm in het stukje waar je de incoming file size ontvangt en afkapt tot MaxChunkSize. Je zult de originele filesize moeten onthouden en aftellen totdat je er geen meer verwacht, wat ook het probleem elimineert dat TijnFlip aangeeft met dat je wellicht doorleest tot in de volgende filetransfer. Tevens maken blocking sockets je leven dan wel heel veel eenvoudiger.

Professionele website nodig?


  • THIJZEL
  • Registratie: Januari 2001
  • Niet online
heeft er iemand dan een voorbeeld van hoe ik het ongeveer dan zou moeten doen, ik kom er namelijk niet helemaal meer uit..

Verwijderd

Luister, je moet ffe goed analyseren waar de fout zit. Als je normaliter brackpoints zet werkt het dus wel. Ik gebruik hier altijd een foutcontrole procedure voor:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
procedure TForm1.GetErrorA;
var
  ErrorCode: DWORD;
  ErrorMessage: Pointer;
begin
  ErrorCode := GetLastError;
  FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER or
  FORMAT_MESSAGE_FROM_SYSTEM, nil, ErrorCode, 0 , @ErrorMessage, 0, nil);
  if Errorcode = 0 then
  begin
        MessageDlg ('Error of: '+S+#13+'GetLastErrorResult:'+IntToStr(ErrorCode)+#13+'Error Discription:'+string(PChar(ErrorMEssage)),mtInformation, [mbOk], 0);
  end
  else
  begin
          MessageDlg ('Error of: '+S+#13+'GetLastErrorResult:'+IntToStr(ErrorCode)+#13+'Error Discription:'+string(PChar(ErrorMEssage)),mtError, [mbOk], 0);
  end;
end;


gebruik: GetErrorA (String) De string mag je een willekurig naampje geven.

als je deze procedure ffe invoegt in je applicatie en deze vervolgens aanroep (zoals boven aangegeven) op de plaatsen waar je normaal de breakpoints zet, zou het best zomaar eens kunnen dat je een foutmelding krijgt.

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

Duidelijker als dit kan ik het echt niet uitleggen hoor zonder dat ik je code voor je schrijf.

Professionele website nodig?

Pagina: 1