I have developed two softwares side by side.
One is a TCP client for iOS devices, which is developed in XCode, the other one is a TCP server for Linux OS, which is developed in Lazarus using Indy 10 as the networking framework.
I can send data between the server and the client with no major problems, however the speed of data transfer from the server to the client is an issue to me.
When sending data from the iOS client to the Linux server I get very good transfer speeds of up to 20 MB a second, but when sending data from the Linux server to the iOS client I get only up to a hundred kilobytes a second (100kb).
Indy 10 sends data in 1024 byte chunks, and I can see that in my iOS app by using NSLog()
.
Question: How can I change the behaviour of Indy 10 to send larger chunks at once?
EDIT:
I am using the following code to send a TMemoryStream
:
procedure TMyClass.SendData(aData: TMemoryStream);
var i: integer;
ctx : TIdContext;
begin
aData.Position := 0;
with fIdTCP.Contexts.LockList do
begin
for i := 0 to Count -1 do //I'm broadcasting the data
begin
ctx := TIdContext(Items[i]);
ctx.Connection.IOHandler.LargeStream:=true;
ctx.Connection.IOHandler.Write(aData, aData.Size, false);
end;
ctx.Connection.IOHandler.WriteBufferClose;
fIdTCP.Contexts.UnlockList;
end
end;
Indy is not the one limiting the size of the sent packets. Its default buffer size is 32K (see the TIdIOHandler.SendBufferSize
property) when reading from the TMemoryStream
(which is limited only by available memory on reads) and then passes however many bytes were read to the underlying socket for sending.
Linux might be the one limiting the size of the sends. The default send buffer size of the underlying socket can be 1024 bytes. The Linux documentation states the following:
socket - Linux socket interface
Socket options
The socket options listed below can be set by using
setsockopt(2)
and read withgetsockopt(2)
with the socket level set toSOL_SOCKET
for all sockets. Unless otherwise noted,optval
is a pointer to anint
....
SO_SNDBUF
Sets or gets the maximum socket send buffer in bytes. The kernel doubles this value (to allow space for bookkeeping overhead) when it is set usingsetsockopt(2)
, and this doubled value is returned bygetsockopt(2)
. The default value is set by the/proc/sys/net/core/wmem_default
file and the maximum allowed value is set by the/proc/sys/net/core/wmem_max
file. The minimum (doubled) value for this option is 2048.
So check if your Linux's wmem_default
/wmem_max
configuration is limiting the transmitted packets to 1024 bytes or not.
You can use Indy's TIdSocketHandle.SetSockOpt()
method to try to specify a different buffer size (within Linux's configured limits), eg:
uses
..., IdStackConsts;
procedure TMyForm.MyTCPServerConnect(AContext: TIdContext);
var
BufferSize: Integer;
begin
BufferSize := ...;
AContext.Binding.SetSockOpt(Id_SOL_SOCKET, Id_SO_SNDBUF, BufferSize);
AContext.Binding.GetSockOpt(Id_SOL_SOCKET, Id_SO_SNDBUF, BufferSize);
// BufferSize now contains the ACTUAL buffer size used by the socket
// which may be different than what you requested...
end;
If the buffer size is not being limited by Linux, then it is likely being limited by iOS when receiving the data. Make sure your iOS app is not limiting its input buffer to 1024 bytes when reading from an NSInputStream
in your stream
event handler.