2012-06-03 2 views
6

Ho bisogno di aiuto per capire come trasferire un record tramite Indy TCP Server/Client. Ho 2 programmi, in I mettere client e in un altro server. Su client su un pulsante ho messo collegare: Il cliente è TIdTCPClientDelphi TidTCPServer e TidTCPClient che trasferiscono un record

Client.Connect(); 

E al lato server Io sono l'aggiunta di una linea a memo che client è connesso, il caso ServerConnect

Protocol.Lines.Add(TimeToStr(Time)+' connected '); 

Per inviare dati da cliente ho un record, che voglio inviare:

Tmyrecord = record 
IPStr: string[15]; 
end; 

e ho un pulsante di invio là:

procedure Tform1.ButtonSendClick(Sender: TObject); 
    var 
    MIRec: Tmyrecord; 
msRecInfo: TMemoryStream; 
begin 
    MIRec.IPStr := '172.0.0.1'; 
    msRecInfo := TMemoryStream.Create; 
    msRecInfo.Write(MIRec, SizeOf(MIRec)); 
    msRecInfo.Position := 0; 
    Client.IOHandler.Write(msRecInfo); 
end; 

Al lato server OnExecute Ho il seguente codice, ho lo stesso tmyrecord dichiarato al lato server troppo:

procedure TServerFrmMain.ServerExecute(AContext: TIdContext); 
var 
    MIRec: Tmyrecord; 
    msRecInfo: TMemoryStream; 
begin 
if AContext.Connection.Connected then 
    begin 
    AContext.Connection.IOHandler.CheckForDataOnSource(10); 
    if not AContext.Connection.IOHandler.InputBufferIsEmpty then 
    begin 
    msRecInfo:= TMemoryStream.Create; 
     AContext.Connection.IOHandler.ReadStream(msRecInfo); 
    msRecInfo.Read(MIRec, sizeOf(msRecInfo)); 
    ShowMessage(MIRec.IPStr); 
end; 
end; 
end 

Non so perché non funziona, perché non posso vedere indirizzo IP che ho scritto dal lato client. Voglio leggere un record (msRecInfo) sul lato server che sto inviando dal lato client. Voglio accedere ai miei elementi del record, in questo caso voglio leggere l'elemento IPSTR del mio record. Quando premo il pulsante di invio da un lato client, l'applicazione si blocca, parte del server.

Grazie mille in anticipo

+0

Sto cercando di inviare un record, msRecInfo, consente di dire quale ha l'elemento IPSTR. Voglio inviare quel record e leggerlo dal server.Voglio leggere IPSTR dal mio record sul lato server –

+0

Solo un suggerimento per ripulire la tua domanda e chiarire che questa è la tua unica domanda. –

+0

Grazie per il suggerimento, modificato la mia domanda, spero sia meglio ora –

risposta

10

si stanno facendo un classico errore newbie - vi aspettate i comportamenti di default dei metodi TIdIOHandler.Write(TStream) e TIdIOHandler.ReadStream() da abbinare tra loro, ma in realtà non è così.

I valori dei parametri di default del TIdIOHandler.ReadStream() dicono che aspettarsi un Integer o Int64 (a seconda del valore della proprietà TIdIOHandler.LargeStream) per precedere i dati di flusso per specificare la lunghezza dei dati.

Tuttavia, i valori dei parametri predefiniti di TIdIOHandler.Write(TStream) non indicano di inviare alcun valore tale Integer/Int64. Pertanto, l'utilizzo di TIdIOHandler.ReadStream() legge i primi pochi byte del record e li interpreta come Integer/Int64 (che è 926036233 dato il valore di stringa che si sta inviando), quindi attende che arrivino molti byte, il che non cambierà mai così TIdIOHandler.ReadStream() esci (a meno che non si imposti la proprietà TIdIOHandler.ReadTimeout su un valore non infinito).

Ci sono anche altri piccoli errori/errori nel codice che utilizzano gli oggetti TMemoryStream al di fuori di Indy.

Prova a modificare:

procedure Tform1.ButtonSendClick(Sender: TObject); 
var 
    MIRec: Tmyrecord; 
    msRecInfo: TMemoryStream; 
begin 
    MIRec.IPStr := '172.0.0.1'; 
    msRecInfo := TMemoryStream.Create; 
    try 
    msRecInfo.Write(MIRec, SizeOf(MIRec)); 

    // writes the stream size then writes the stream data 
    Client.IOHandler.Write(msRecInfo, 0, True); 
    finally 
    msRecInfo.Free; 
    end; 
end; 

procedure TServerFrmMain.ServerExecute(AContext: TIdContext); 
var 
    MIRec: Tmyrecord; 
    msRecInfo: TMemoryStream; 
begin 
    msRecInfo := TMemoryStream.Create; 
    try 
    // reads the stream size then reads the stream data 
    AContext.Connection.IOHandler.ReadStream(msRecInfo, -1, False); 

    msRecInfo.Position := 0; 
    msRecInfo.Read(MIRec, SizeOf(MIRec)); 
    ... 
    finally 
    msRecInfo.Free; 
    end; 
end; 

O questo:

procedure Tform1.ButtonSendClick(Sender: TObject); 
var 
    MIRec: Tmyrecord; 
    msRecInfo: TMemoryStream; 
begin 
    MIRec.IPStr := '172.0.0.1'; 
    msRecInfo := TMemoryStream.Create; 
    try 
    msRecInfo.Write(MIRec, SizeOf(MIRec)); 

    // does not write the stream size, just the stream data 
    Client.IOHandler.Write(msRecInfo, 0, False); 
    finally 
    msRecInfo.Free; 
    end; 
end; 

procedure TServerFrmMain.ServerExecute(AContext: TIdContext); 
var 
    MIRec: Tmyrecord; 
    msRecInfo: TMemoryStream; 
begin 
    msRecInfo := TMemoryStream.Create; 
    try 
    // does not read the stream size, just the stream data 
    AContext.Connection.IOHandler.ReadStream(msRecInfo, SizeOf(MIRec), False); 

    msRecInfo.Position := 0; 
    msRecInfo.Read(MIRec, SizeOf(MIRec)); 
    ... 
    finally 
    msRecInfo.Free; 
    end; 
end; 

In alternativa, è possibile inviare il record utilizzando TIdBytes invece di TStream:

procedure Tform1.ButtonSendClick(Sender: TObject); 
var 
    MIRec: Tmyrecord; 
    Buffer: TIdBytes; 
begin 
    MIRec.IPStr := '172.0.0.1'; 
    Buffer := RawToBytes(MIRec, SizeOf(MIRec)); 
    Client.IOHandler.Write(Buffer); 
end; 

procedure TServerFrmMain.ServerExecute(AContext: TIdContext); 
var 
    MIRec: Tmyrecord; 
    Buffer: TIdBytes; 
begin 
    AContext.Connection.IOHandler.ReadBytes(Buffer, SizeOf(MIRec)); 
    BytesToRaw(Buffer, MIRec, SizeOf(MIRec)); 
    ... 
end; 
+0

Proverò l'ultimo, che sembra fantastico, grazie –