【发布时间】:2016-01-05 02:02:18
【问题描述】:
我同时开发了两个软件。
一个是iOS设备的TCP客户端,是用XCode开发的, 另一个是 Linux OS 的 TCP 服务器,它是在 Lazarus 中使用 Indy 10 作为网络框架开发的。
我可以在服务器和客户端之间发送数据而没有大问题, 但是从服务器到客户端的数据传输速度对我来说是个问题。
当从 iOS 客户端向 Linux 服务器发送数据时,我获得了高达每秒 20 MB 的非常好的传输速度, 但是当从 Linux 服务器向 iOS 客户端发送数据时,我每秒最多只能获得 100 KB (100kb)。
Indy 10 以 1024 字节块发送数据,我可以在我的 iOS 应用程序中使用 NSLog() 看到这一点。
问题:如何更改 Indy 10 的行为以一次发送更大的块?
编辑:
我正在使用以下代码发送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 发送到 iOS?你在做什么方法调用?您使用的是 SSL/TLS 吗?这样的事情会有所作为。 Indy 不使用 1KB 缓冲区,除非您告诉它。如果有的话,它的默认缓冲区大小是 32K。因此,Indy 之外的某些东西可能会限制数据大小,具体取决于您的数据来自哪里以及您发送数据的方式。
-
我更新了问题并添加了代码。没错,缓冲区大小是 32K,我可以测量并更改它,但 iOS 应用程序仍会收到 1024 kb 块。
-
首先,您不应该在没有之前的
WriteBufferOpen()的情况下调用WriteBufferClose()(并且在发送TStream数据时不应该使用写缓冲)。其次,UnlockList()需要在try/finally块中,因为Write()可以引发异常。如果客户端断开连接/失败,如果您不解锁列表,您将导致死锁。第三,如果一个客户端出现故障,您不会处理它,因此您最终会跳过广播中的所有后续客户端。仅供参考,这不是使用 Indy 处理 TCP 广播的最佳方式。 -
在任何情况下,
TIdIOHandler.Write(TStream)分配一个(默认)32K 缓冲区并从TStream读取该大小的块,将实际上读取的许多字节发送到底层套接字。TMemoryStream没有 1024K 的读取限制,Indy 也没有。但是底层套接字可能会对发送施加 1024K 的限制,具体取决于其内部缓冲区大小。您可以使用AContext.Binding.SetSocketOpt(Id_SOL_SOCKET, Id_SO_SNDBUF, ...)设置该缓冲区大小。或者尝试设置AContext.Connection.Socket.UseNagle := False。 -
感谢您的意见,我会按照您的建议去做。那么
SetSocketOpt究竟是如何工作的,我应该写什么来改变内部缓冲区大小?
标签: linux performance tcp lazarus indy10