Entwickler-Ecke

Internet / Netzwerk - Mit SendBuf (Sockets) Binäre Dateien verschicken.


O'rallY - Fr 27.09.02 17:42
Titel: Mit SendBuf (Sockets) Binäre Dateien verschicken.
Wie kann man, unter der verwendung von Socket.SendBuf(...) eine binäre Datei verschicken. Bisher habe ich das ganze so gemacht , doch funktioniert das nur bei Textdateien:

Quelltext
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:
procedure aProcedure;
var
   temp: string;
   i, PacketSize, FSize, SizeAlreadyTransferred: integer;
   FileStream: TFileStream

begin   


  FileStream := TFileStream.Create('C:\datei.txt', fmOpenRead);
  FileStream.Read(PChar(temp)^, FileStream.Size);
  FileStream.Free;


  PacketSize := 4096;
  FSize := Length(temp);

  for i := 0 to FSize div PacketSize do
  begin
     if i = FSize div PacketSize then
        PacketSize := FSize - SizeAlreadyTransferred;
     end;

     ClientSocket1.Socket.SendBuf(PChar(temp)^, PacketSize);

     temp := RightStr(temp, Length(temp) - PacketSize);

     Inc(SizeAlreadyTransferred, PacketSize);

   end;

end;


//server:
var
temp: string;
FileStream: TFileStream;

begin
  temp := Socket.ReceiveText;
  FileStream := TFileStream.Create('C:\datei.txt', fmCreate or fmOpenReadWrite);
  FileStream.Write(Pchar(temp)^, Length(temp);
  FileStream.Free;
end;


Das das nur mit Textdateien funktioniert ist ja auch logisch, doch weiß ich eben nicht wie das ganze mir Binärdaten funktioniert (habe nur wage vorstellungen). Ich erbitte HILFE :!:

P.S.: falls diese Frage schon des Öfteren gestellt wurde, tut mir Leid, aber die Suchfunktion ist nicht sehr ergiebig. Um genau zu sein ist sie zum
:puke:


DeCodeGuru - Fr 27.09.02 18:54

Hi,

du musst die Daten ja nicht unbedingt in einen String auslagern. Das kann eben zu dem Fehler kommen, dass man binäre Daten nicht übertragen kann. Du könntest zum Beispiel auch mit ClientSocket1.Socket.SendBuf(FileStream^,SizeOf(FileStream)); senden. Ansonsten könntest du dein temp-var auch als array of Byte deklarieren. Dann dürfte kein Fehler mehr auftreten.

So, hier habe ich nochmal eine relativ alte Sendenroutine (Server und Client im selben Programm):


Quelltext
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:
procedure TMainForm.ClientRead(Sender: TObject; Socket: TCustomWinSocket);
var
  tmp: String;
  FStream: TMemoryStream;
  Buf: Pointer;
begin
  case CSendStatus of
    0:
    begin
      tmp := Socket.ReceiveText;
      if Copy(tmp,1,3) = '#11' then
      begin
        CSendStatus := 1;
        FStream := TMemoryStream.Create;
        FStream.LoadFromFile(Edit2.Text);
        Socket.SendText('#02'+IntToStr(FStream.Size));
        FStream.Free;
      end;
      if Copy(tmp,1,3) = '#12' then
      begin
        CSendStatus := 0;
      end;
    end;
    1:
    begin
      tmp := Socket.ReceiveText;
      if Copy(tmp,1,3) = '#13' then
      begin
        Socket.SendText('#03');
        CSendStatus := 2;
      end;
      if Copy(tmp,1,3) = '#14' then
      begin
        CSendStatus := 0;
      end;
    end;
    2:
    begin
      tmp := Socket.ReceiveText;
      if Copy(tmp,1,3) = '#15' then
      begin
        FStream := TMemoryStream.Create;
        FStream.LoadFromFile(Edit2.Text);
        Buf := FStream.Memory;
        Socket.SendBuf(Buf^,FStream.Size);
      end;
    end;
  end;
end;

procedure TMainForm.ServerClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
  tmp: String;
  a: array[0..4096]of Byte;
  Buf: Pointer;
  i: Integer;
begin
  case SSendStatus of
    0:
    begin
      tmp := Socket.ReceiveText;
      if Copy(tmp,1,3) = '#01' then
      begin
        if MessageDlg('Ein Client will Ihnen eine Datei schicken. Wollen Sie die Dateiübertragung akzeptieren?',mtConfirmation,[mbYes,mbNo],0) = mrYes then
        begin
          Delete(tmp,1,3);
          Form3.Label1.Caption := 'Dateiname: '+tmp;
          FileName := tmp;
          SSendStatus := 1;
          Socket.SendText('#11');
          FSize := 0;
          FPos := 0;
        end
        else
        begin
          SSendStatus := 0;
          Socket.SendText('#12');
        end;
      end;
    end;
    1:
    begin
      tmp := Socket.ReceiveText;
      if Copy(tmp,1,3) = '#02' then
      begin
        Delete(tmp,1,3);
        FSize := StrToInt(tmp);
        SSendStatus := 2;
        Socket.SendText('#13');
        Form3.Label2.Caption := 'Fortschritt: 0 von '+IntToStr(FSize);
        Form3.Gauge1.MaxValue := FSize;
      end
      else
      begin
        SSendStatus := 1;
        Socket.SendText('#14');
      end;
    end;
    2:
    begin
      tmp := Socket.ReceiveText;
      if Copy(tmp,1,3) = '#03' then
      begin
        SaveDialog.FileName := ExtractFileName(FileName);
        if SaveDialog.Execute then
        begin
          SSendStatus := 3;
          Socket.SendText('#15');
          TMPStream := TFileStream.Create(SaveDialog.FileName,fmCreate or fmOpenWrite);
        end;  
      end;
    end;
    3:
    begin
      Timer.Enabled := True;
      Form3.Show;  //Fortschrittsanzeige
      Buf := @a;
      i := Socket.ReceiveBuf(Buf^,4096);
      TMPStream.Write(Buf^,i);
      FPos := FPos +i;
      Form3.Gauge1.Progress := FPos;
      Form3.Label2.Caption := 'Fortschritt: '+IntToStr(FPos)+' von '+IntToStr(FSize);      if FPos >= FSize then
      begin
        TMPStream.Position := 0;
        FPos := 0;
        SSendStatus := 0;
        Timer.Enabled := False;
      end;
    end;
  end;
end;


Ich denke, dass man alles aus dem Quelltext entnehmen kann. Wenn nicht bitte fragen.


O'rallY - Fr 27.09.02 19:47

DeCodeGuru hat folgendes geschrieben:
du musst die Daten ja nicht unbedingt in einen String auslagern

Dessen war ich mir im Klaren, doch wusste ich nicht, wie eine Alternative genau aussieht. Aber dank dir hab ichs jetzt geschnackelt. Ich dank dir :mrgreen: .


DeCodeGuru - Fr 27.09.02 19:49

bitte :wink:


O'rallY - Fr 27.09.02 22:52

OK, habs jetzt alles nach deinem Vorschlag umgestalltet, doch bekomme ich nun, wenn ich die Datei schicken will einen Asyncronous Socket Error (10053) Eine bestehende Verbindung wurde Softwaregesteuert durch den Hostcomputer abgebrochen


DeCodeGuru - Sa 28.09.02 09:26

hast du den gleichen Code verwendet? wenn ja könnte es an paar anderen Routinen liegne, die noch im Programm sind. Ich wollte mit dem Quellcode nur ein kleines Beispiel geben, wie man so etwas machen kann. Wenn du willst, kann ich dir das Programm mal schicken.


O'rallY - Sa 28.09.02 12:40

Wäre nett wenn du mir mal das Programm schicken würdest. Trotzdem erstmal mein Code:

Quelltext
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:
procedure TForm1.ClientSocket1Connect(Sender: TObject;
  Socket: TCustomWinSocket);
  var
     MStream: TMemoryStream;
     Buffer: Pointer;

  begin

  MStream := TMemoryStream.Create;
  MStream.LoadFromFile('C:\dateiin.txt');
  Buffer := MStream.Memory;
  Socket.SendBuf(Buffer^, MStream.Size);

end;

procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
   fs: TFileStream;
   Buffer: pointer;
   BBuffer: array[0..4096] of Byte;
   SizeOfBuffer: integer;

begin

   fs := TFileStream.Create('c:\dateiout.txt', fmCreate or fmOpenWrite);
   Buffer := @BBuffer;
   SizeOfBuffer := Socket.ReceiveBuf(Buffer^, 4096);
   fs.Write(Buffer^, SizeOfBuffer);
end;


Der von mir beschriebene Fehler tritt nicht auf, wenn ich beim OnClientConnet-Event folgenden Code austausche:

Quelltext
1:
2:
3:
4:
   Socket.SendBuf(Buffer^, MStream.Size);
                            |
                            v
   Socket.SendBuf(Buffer^, 4096);


Ich vermute, es liegt daran, dass das OnClientRead-Event nur einmal ausgeführt wird und somit nur 4096 Bytes aus dem gesendeten ausliest, obwohl der Client mehr gesendet hat. Dummerweise kenne ich mich mit Socket.ReceiveBuf(...) nicht so gut aus.[/code]


DeCodeGuru - Sa 28.09.02 13:16

jo ähm, könnteste du mir deine Mailadresse per PN schicken?


O'rallY - Sa 28.09.02 23:02

Zitat:

Der von mir beschriebene Fehler tritt nicht auf, wenn ich beim OnClientConnet-Event folgenden Code austausche:

Quelltext
1:
2:
3:
4:
  Socket.SendBuf(Buffer^, MStream.Size);
              |
              v
  Socket.SendBuf(Buffer^, 4096);



Um genau zu sein tritt der Fehler erst auf, wenn MStream.Size > 233472 ist. Es hat also nichts mit den 4096 Bytes zu tun. Ist das so normal oder nicht? Hat es einen Hintergrund?
Wäre nett wenn mal ein anderer ausprobieren würde eine Datei zu schicken, die über 240000 Byte groß ist und mir dann sagen, obs geklappt hat oder nicht!


O'rallY - So 29.09.02 09:22
Titel: Problem gelöst!
Ich hab gerade das Problem gelöst! *stolz* Da SendBuf ja nur begrenzt nutzbar zu sein scheint (im Sinne der Dateigröße), hab ich mal das ganze mit SendStream ausprobiert. Das sieht dann etwa so aus:

Quelltext
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:
procedure TForm1.ClientSocket1Connect(Sender: TObject;
 Socket: TCustomWinSocket);
 var
   FStream: TFileStream;

 begin

 FStream := TFileStream.Create('C:\dateiin.txt', fmOpenRead);
 Socket.SendStream(FStream);

end;

procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
 Socket: TCustomWinSocket);
var
  fs: TFileStream;
  Buffer: pointer;
  BBuffer: array[0..4096] of Byte;
  SizeOfBuffer: integer;

begin

  fs := TFileStream.Create('c:\dateiout.txt', fmCreate or fmOpenWrite);
  Buffer := @BBuffer;
  SizeOfBuffer := Socket.ReceiveBuf(Buffer^, 4096);
  fs.Write(Buffer^, SizeOfBuffer);
end;


Manchmal ist es schon verwunderlich, wie einfach ein Problem zu lösen ist (und wie depremierend eine einfache Lösung sein kann :? ) :mrgreen:. Das dumme ist, wenn man an einem Problem sitzt und versucht es zu lösen, kann es leicht passieren, das man sich festfährt und die vielleicht viel simplere Lösung nicht sieht :)


DeCodeGuru - So 29.09.02 10:38

ich will dich ja nicht enttäuschen, aber mit meiner Methode (über SendBuf)
habe ich schon Dateien um die 100MB geschickt -> es ist durchaus mit SendBuf möglich.


O'rallY - So 29.09.02 13:50

Verdammt! *g* Ich bleib trotzdem bei SendStream. Wozu hat man es denn... :mrgreen:


DeCodeGuru - So 29.09.02 15:17

hast recht