Write buffering is disabled by default. You can check write buffering to see if it's active in your code by testing the fConnection.IOHandler.WriteBufferingActive property.
As far as the best way to send an integer... 'it depends' on your protocol and overall goals. Specifically, use FConnection.IOHandler.Write() as there are overloaded methods to write just about any type of data, including an integer.
Taken from IdIOHandler:
// Optimal Extra Methods
//
// These methods are based on the core methods. While they can be
// overridden, they are so simple that it is rare a more optimal method can
// be implemented. Because of this they are not overrideable.
//
//
// Write Methods
//
// Only the ones that have a hope of being better optimized in descendants
// have been marked virtual
procedure Write(const AOut: string; const AEncoding: TIdEncoding = enDefault); overload; virtual;
procedure WriteLn(const AEncoding: TIdEncoding = enDefault); overload;
procedure WriteLn(const AOut: string; const AEncoding: TIdEncoding = enDefault); overload; virtual;
procedure WriteLnRFC(const AOut: string = ''; const AEncoding: TIdEncoding = enDefault); virtual;
procedure Write(AValue: TStrings; AWriteLinesCount: Boolean = False; const AEncoding: TIdEncoding = enDefault); overload; virtual;
procedure Write(AValue: Byte); overload;
procedure Write(AValue: Char; const AEncoding: TIdEncoding = enDefault); overload;
procedure Write(AValue: LongWord; AConvert: Boolean = True); overload;
procedure Write(AValue: LongInt; AConvert: Boolean = True); overload;
procedure Write(AValue: SmallInt; AConvert: Boolean = True); overload;
procedure Write(AValue: Int64; AConvert: Boolean = True); overload;
procedure Write(AStream: TStream; ASize: Int64 = 0; AWriteByteCount: Boolean = False); overload; virtual;
Another question you had was "Does it make a difference whether I use multiple write commands in a row or pack things together in a byte array and send that once?" For the majority of cases, yes it makes a difference. For highly stressed servers you are going to have to get more involved in how bytes are sent back and forth, but at this level you should abstract out your sends into a separate protocol type class that builds the data to be sent and sends it in a burst and have a receiving protocol that receives a bunch of data and processes it as a complete unit instead of breaking things down to sending/receiving an integer, character, byte array, etc..
As a very rough quick example:
TmyCommand = class(TmyProtocol)
private
fCommand:Integer;
fParameter:String;
fDestinationID:String;
fSourceID:String;
fWhatever:Integer;
public
property Command:Integer read fCommand write fCommand;
...
function Serialize;
procedure Deserialize(Packet:String);
end;
function TmyCommand.Serialize:String;
begin
//you'll need to delimit these to break them apart on the other side
result := AddItem(Command) +
AddItem(Parameter) +
AddItem(DestinationID) +
AddItem(SourceID) +
AddItem(Whatever);
end;
procedure TMyCommand.Deserialize(Packet:String);
begin
Command := StrToInt(StripOutItem(Packet));
Parameter := StripOutItem(Packet);
DesintationID := StripOutItem(Packet);
SourceID := StripOutItem(Packet);
Whatever := StrToInt(StripOutItem(Packet));
end;
Then send this via:
FConnection.IOHandler.Write(myCommand.Serialize());
On the other side you can receive the data via Indy and then
myCommand.Deserialize(ReceivedData);
The two sample links on the Indy Demos page are dead links
The only dead link on that page is Ralph's TIdTCPClient/Server with SSL
demo. The other links work fine, including the one to TCP/IP Delphi&Indy10 Client Server Demo
.
I have been unable to find any sample code after extensive searching.
Then you are not searching very well, because there have been tons of examples posted in the Embarcadero and Indy forums, and even here on StackOverflow.
I have been able to guess based on the member functions of TIdTCPClient to write id1->Socket->WriteLn
to send something which gets received by the server but have not yet figured out how to receive the server's response.
TIdTCPClient
is not an asynchronous component. It reads only when you tell it to read. Assuming your WriteLn()
is sending a request, you can call ReadLn()
(or whatever reading method you want) immediately after WriteLn()
exits, eg:
id1->Socket->WriteLn("JSON data here");
String response = id1->Socket->ReadLn();
If you want to read responses asynchronously, do the reading in a separate worker thread.
Also, is there any overview documentation for Indy TCP client?
The official documentation is on Indy's website:
http://www.indyproject.org/Sockets/Docs/index.aspx
http://www.indyproject.org/docsite/html
The documentation is a bit old, especially the class reference portion, but the overviews still largely apply.
In some Delphi snippets I saw id1.IOHandler.WriteLn
used instead but I don't see any explanation of what IOHandler is for, which one I should use, what the difference is between IOHandler.WriteLn and Socket.WriteLn, etc.
The Socket
property is provided for convenience. When the IOHandler
property points at a TIdIOHandlerSocket
object, the Socket
property returns that same object. This avoids any need to type-cast the IOHandler
to access any socket-specific functionality. Indy implements several IOHandler
s other than for socket I/O, and you can write custom IOHandler
s as well.
The IOHandler
does all the real work. You should use the IOHandler
property instead of the Socket
property when accessing any IO-agnostic methods, like WriteLn()
and ReadLn()
. This way, you can swap out different IOHandler
objects at will. This is useful, for instance, when capturing socket activity and replaying it for debugging purposes.
Best Answer
The page you cite doesn't reproduce the messages very well. Here's what Remy really wrote:
The
Write
methods he was talking about are members of theTIdIOHandler
class. YourTIdTCPConnection
object has an instance of that class in itsIOHandler
property, and indeed that's what theSendCmd
function uses to send its string.The notation
Write(TIdBytes)
means to use theWrite
method that accepts aTIdBytes
parameter for its input.If the binary data is already in a stream or a dynamic array of bytes, then you can pass one of those directly to the
Write
method. There's also theWriteFile
method that will send an entire external file if you provide the file's name. If you use the stream version, then you have the option of including the stream's length automatically.If you don't have your data in one of those structures already, then you can either write the data piecemeal with the
Write
methods that accept variously sized integer types, or you can copy your data into aTMemoryStream
and then pass that toWrite
.