首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >如何在TIdTcpServer和TIdTCPClient (如洪水)之间快速交换数据

如何在TIdTcpServer和TIdTCPClient (如洪水)之间快速交换数据
EN

Stack Overflow用户
提问于 2020-12-29 09:31:07
回答 1查看 349关注 0票数 4

我有一个简单的TidTCPServer在控制台上工作并接受数据。我的问题是当客户端发送流,但是有很高的速度交换数据时,服务器在70行之后冻结,服务器的CPU负载达到70%;我不知道如何解决,而不增加每次发送之间的睡眠。下面是客户机和服务器的示例。你能帮我解决这个(服务器端)谢谢。

代码语言:javascript
运行
AI代码解释
复制
program Srv;

{$I Synopse.inc}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes, SysUtils, CustApp, Generics.Collections, IdTCPServer, IdCustomTCPServer, IdContext, IdGlobal, Db, mORMot, mORMotSQLite3, IdSync, functions, SynCommons, SynSQLite3Static;

type

  { TMyApplication }
  TMyApplication = class(TCustomApplication)

   var IdTCPServer: TIdTCPServer;

   protected
    procedure DoRun; override;
    procedure ServerOnConnect(AContext: TIdContext);
    procedure ServerOnExecute(AContext: TIdContext);
    function ReceiveStream(AContext: TIdContext;Size:integer; var AStream: TStream);

  public
    constructor Create(TheOwner: TComponent); override;
    destructor Destroy; override;
  end;

  type
    TLog = class(TIdNotify)
    protected
      FMsg: string;
      procedure DoNotify; override;
    public
      class procedure LogMsg(const AMsg: string);
    end;

{ TMyApplication }

    procedure TLog.DoNotify;
    var i:integer;
    begin
     writeln(FMsg);
    end;

    class procedure TLog.LogMsg(const AMsg: string);
    begin
      with TLog.Create do
      try
        FMsg := AMsg;
        Notify;
      except
        Free;
        raise;
      end;
    end;

function TMyApplication.ReceiveStream(AContext: TIdContext; var AStream: TStream)
  : Boolean; overload;
var
  LSize: LongInt;
begin
  Result := True;
  try
    LSize := AContext.Connection.IOHandler.ReadLongInt();
    AContext.Connection.IOHandler.ReadStream(AStream,LSize, False)
    AStream.Seek(0,soFromBeginning);
  except
    Result := False;
  end;
end;      

procedure TMyApplication.ServerOnExecute(AContext: TIdContext);
var AStream:TMemoryStream;
begin

if (Acontext.Connection.IOHandler.InputBufferIsEmpty) then
  begin
    TLog.LogMsg('--: '+random(100000).ToString); //After executing Client this line is displayed 70 time and CPU load is from 40 % to 70%
    AStream:=TMemoryStream.Create;
    try 
      ReceiveStream(AContext,TStream(AStream)); 
      // .. here we use AStream to execute some stuff  
    finally
      Astream.free;
    end;        
end;

procedure TMyApplication.ServerOnConnect(AContext: TIdContext);
begin
 TLog.LogMsg('connect');        
end;

procedure TMyApplication.DoRun;
begin

    IdTCPServer := tIdTCPServer.Create;
    IdTCPServer.ListenQueue := 15;
    IdTCPServer.MaxConnections := 0;
    IdTCPServer.TerminateWaitTime := 5000;
    with IdTCPServer.Bindings.Add
    do begin
      IP   := '0.0.0.0';
      Port := 80;
      IPVersion:=Id_IPv4;
    end;
    IdTCPServer.OnConnect := ServerOnConnect;
    IdTCPServer.OnDisconnect := ServerOnDiconnect;
    IdTCPServer.OnExecute := ServerOnExecute;
    IdTCPServer.Active := True;

  while true do
   begin
    Classes.CheckSynchronize() ;
    sleep(10);
   end;

  readln;        

  Terminate;
end;

constructor TMyApplication.Create(TheOwner: TComponent);
begin

  inherited Create(TheOwner);
  StopOnException := True;

end;


destructor TMyApplication.Destroy;
begin
  IdTCPServer.Free;
  inherited Destroy;

end;

var
  Application: TMyApplication;
begin
  Application := TMyApplication.Create(nil);
  Application.Title := 'My Application';
  Application.Run;
  Application.Free;
end.

客户端

代码语言:javascript
运行
AI代码解释
复制
function TForm1.SendStream(AClient: TIdTCPClient; AStream: TStream): Boolean; overload;
var
  StreamSize: LongInt;
begin
  try
    Result := True;
    try
      AStream.Seek(0,soFromBeginning);
      StreamSize := (AStream.Size);
      AClient.IOHandler.Write(LongInt(StreamSize));
      AClient.IOHandler.WriteBufferOpen;
      AClient.IOHandler.Write(AStream, 0, False);
      AClient.IOHandler.WriteBufferFlush;
    finally
      AClient.IOHandler.WriteBufferClose;
    end;
  except
    Result := False;
  end;
end;   
    
procedure TForm1.Button1Click(Sender: TObject);
var 
  Packet:TPacket;
  AStream:TMemoryStream;
begin
for i:=0 to 1000 do 
  begin
    Application.ProcessMessages;
    With Packet do
                 begin
                   MX               := random(10000);
                   MY               := random(10000);
                 end;
     AStream:=TMemoryStream.Create;
     try
        AStream.Write(Packet,SizeOf(TPacket));
        SendStream(IdTCPClientCmd,TStream(AStream));
     finally
        AStream.Free;
     end;
  end;

end;                
EN

回答 1

Stack Overflow用户

发布于 2020-12-29 10:26:55

在服务器端,您的InputBufferIsEmpty()检查是向后的。如果客户端发送了大量数据,InputBufferIsEmpty()可能最终会变成False,这将导致服务器代码进入一个严格的、不需要读取任何内容的循环。只需完全摆脱检查,让ReceiveStream()阻塞,直到有可用的数据包可阅读。

另外,为什么要将服务器的ListenQueue设置为15,而将MaxConnections设置为0呢?MaxConnections=0将迫使服务器立即关闭每个已被接受的客户端连接,因此OnExecute事件将永远不会被调用。

在客户端,没有必要在每次循环迭代中销毁和重新创建TMemoryStream,您应该重用该对象。

但是更重要的是,您没有正确地使用写缓冲,所以要么修复它,要么摆脱它。我会做后者,因为您正在发送大量的小数据包,所以让TCP的默认合并处理缓冲。

TIdIOHandler.Write(TStream)/TIdIOHandler.ReadStream()可以为您交换流大小,不需要手动执行。

试一试:

服务器

代码语言:javascript
运行
AI代码解释
复制
program Srv;

{$I Synopse.inc}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes, SysUtils, CustApp, Generics.Collections, IdTCPServer, IdCustomTCPServer, IdContext, IdGlobal, Db, mORMot, mORMotSQLite3, IdSync, functions, SynCommons, SynSQLite3Static;

type

  { TMyApplication }
  TMyApplication = class(TCustomApplication)
  var
    IdTCPServer: TIdTCPServer;
  protected
    procedure DoRun; override;
    procedure ServerOnConnect(AContext: TIdContext);
    procedure ServerOnExecute(AContext: TIdContext);
    function ReceiveStream(AContext: TIdContext; Size: Integer; var AStream: TStream);
  public
    constructor Create(TheOwner: TComponent); override;
    destructor Destroy; override;
  end;

  type
    TLog = class(TIdNotify)
    protected
      FMsg: string;
      procedure DoNotify; override;
    public
      class procedure LogMsg(const AMsg: string);
    end;

{ TMyApplication }

procedure TLog.DoNotify;
begin
  WriteLn(FMsg);
end;

class procedure TLog.LogMsg(const AMsg: string);
begin
  with TLog.Create do
  try
    FMsg := AMsg;
    Notify;
  except
    Free;
    raise;
  end;
end;

function TMyApplication.ReceiveStream(AContext: TIdContext; AStream: TStream): Boolean; overload;
begin
  try
    AContext.Connection.IOHandler.ReadStream(AStream, -1, False);
    AStream.Position := 0;
    Result := True;
  except
    Result := False;
  end;
end;      

procedure TMyApplication.ServerOnExecute(AContext: TIdContext);
var
  AStream: TMemoryStream;
begin
  AStream := TMemoryStream.Create;
  try 
    if not ReceiveStream(AContext, AStream) then
    begin
      AContext.Connection.Disconnect;
      Exit;
    end;
    TLog.LogMsg('--: '+random(100000).ToString); //After executing Client this line is displayed 70 time and CPU load is from 40 % to 70%
    // .. here we use AStream to execute some stuff  
  finally
    AStream.Free;
  end;        
end;

procedure TMyApplication.ServerOnConnect(AContext: TIdContext);
begin
  TLog.LogMsg('connect');        
  AContext.Connection.IOHandler.LargeStream := False;
end;

procedure TMyApplication.DoRun;
begin
  IdTCPServer := TIdTCPServer.Create;
  IdTCPServer.ListenQueue := 15;
  IdTCPServer.MaxConnections := 1;
  IdTCPServer.TerminateWaitTime := 5000;
  with IdTCPServer.Bindings.Add do
  begin
    IP   := '0.0.0.0';
    Port := 80;
    IPVersion := Id_IPv4;
  end;
  IdTCPServer.OnConnect := ServerOnConnect;
  IdTCPServer.OnDisconnect := ServerOnDiconnect;
  IdTCPServer.OnExecute := ServerOnExecute;
  IdTCPServer.Active := True;

  while True do
  begin
    Classes.CheckSynchronize();
    Sleep(10);
  end;

  ReadLn;
  Terminate;
end;

constructor TMyApplication.Create(TheOwner: TComponent);
begin
  inherited Create(TheOwner);
  StopOnException := True;
end;

destructor TMyApplication.Destroy;
begin
  IdTCPServer.Free;
  inherited Destroy;
end;

var
  Application: TMyApplication;
begin
  Application := TMyApplication.Create(nil);
  Application.Title := 'My Application';
  Application.Run;
  Application.Free;
end.

客户端

代码语言:javascript
运行
AI代码解释
复制
function TForm1.SendStream(AClient: TIdTCPClient; AStream: TStream): Boolean; overload;
begin
  try
    AClient.IOHandler.LargeStream := False; // <-- or, set this 1 time after TIdTCPClient.Connect() exits...
    AClient.IOHandler.Write(AStream, 0, True);
    Result := True;
  except
    Result := False;
  end;
end;   
    
procedure TForm1.Button1Click(Sender: TObject);
var 
  Packet: TPacket;
  AStream: TMemoryStream;
  i: Integer;
begin
  AStream := TMemoryStream.Create;
  try
    AStream.Size := SizeOf(TPacket);
    for i := 0 to 1000 do 
    begin
      Application.ProcessMessages;
      with Packet do
      begin
        MX := random(10000);
        MY := random(10000);
      end;
      AStream.Position := 0;
      AStream.Write(Packet, SizeOf(TPacket));
      SendStream(IdTCPClientCmd, AStream);
    end;
  finally
    AStream.Free;
  end;
end;                
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65496255

复制
相关文章
Python异常处理traceback和exc_info
开发过程中一般都会使用traceback将捕获到的异常打印出来。 import traceback def fake_exception(): 1 / 0 def catch_exception(): try: fake_exception() except: traceback.print_exc() catch_exception() 结果 Traceback (most recent call last): File ".\test.p
Ewdager
2020/07/14
6490
Python 日志打印之logging.config.dictConfig使用总结
dictConfig函数位于logging.config模块,该函数通过字典参数config对logging进行配置。3.2版本新增的函数
授客
2021/01/13
4.1K2
11 | Tornado源码分析:Gen 对象(下)
我们先看一下源码(我已经进行过整理的源码,主要方面大家去理解里面的实现逻辑,若想看完整的源码建议大家可以自行查看本机安装的 tornado 版本中的源代码),在源码中我做了一些批注,这样有利于大家更好的去结合代码来深入了解 其内部的运作。
python编程从入门到实践
2020/09/09
4260
Openstack之log详解
openstack中的日志由oslo_log统一实现,延续了openstack一贯的封装大法,以十分友好的方式将接口提供给各个组件使用。
tunsuy
2022/10/27
4940
[源码解析] PyTorch 流水线并行实现 (6)--并行计算
前几篇文章我们介绍了 PyTorch 流水线并行的基本知识,自动平衡机制和切分数据,本文我们结合论文内容来看看如何实现流水线。
罗西的思考
2021/10/13
1.5K0
12 | Tornado源码分析:BaseIOStream 对象(上)
hello 大家好 通过前几期我们已经聊了 Tornado 中协程的创建、运行,本期我们开始聊聊 tornado 中 网络读写数据处理相关的内容,这部分还是比较复杂的我们打算拆分成几期来聊。
python编程从入门到实践
2020/09/16
4630
PyTorch 源码解读之流水线并行
如图所示为谷歌提出的流水线并行算法,名为 GPipe,论文位于 https://arxiv.org/abs/1811.06965。首先将模型切分为连续的多个 stage,每个 stage 占据一台设备,从而利用多台设备容纳下单设备无法容纳的模型。其次,GPipe 将 mini-batch 切分为多个 micro-batch,每次只处理一个 micro-batch。在处理完当个 micro-batch 后,该 micro-batch 的结果将会被发送给下一台设备,同时开始处理下一个 micro-batch。
OpenMMLab 官方账号
2023/09/28
8320
PyTorch 源码解读之流水线并行
uwsgi日志中文问题
开发项目,使用uwsgi,遇到个头痛的问题,如果指定了uwsgi打印日志,当日志中写入中文时,直接会导致报错
fanspring
2019/06/27
1.7K0
Python常用库 - logging日志库
logging 使用非常简单,使用 basicConfig() 方法就能满足基本的使用需要;如果方法没有传入参数,会根据默认的配置创建Logger 对象,默认的日志级别被设置为 WARNING,该函数可选的参数如下表所示。
小菠萝测试笔记
2020/06/09
8540
如何扩展python的logging组件支持json日志输出
这两天在优化公司一个python的项目,顺便研究了一下如何将python日志转成json格式,原来在Java的项目中搞过类似的事情,知道日志转成json之后有很多便利的之处,最常见的就是可以直接对接各种日志分析系统,如开源的ELK,将数据导入之后就能快速的进行查询和分析,方便做各种统计,监控或报警等。
我是攻城师
2019/03/06
3.1K0
如何扩展python的logging组件支持json日志输出
Python Web开发中的WSGI协议
 在Python Web开发中,我们一般使用Flask、Django等web框架来开发应用程序,生产环境中将应用部署到Apache、Nginx等web服务器时,还需要uWSGI或者Gunicorn。一个完整的部署应该类似这样:
py3study
2020/01/16
9170
09 | Tornado源码分析:Future 对象
今天我们来看一下 Future 这个对象。从字面意思来看有“未来,将来......”之意义。那它在Tornado 构建的体系中扮演者什么样的角色呢?我们先看一下它的源码:
python编程从入门到实践
2020/07/28
8750
python 查找指定目录下的指定类型文件 脚本
""" Find the largest file of a given type in an arbitrary directory tree. Avoid repeat paths, catch errors, add tracing and line count size. Also uses sets, file iterators and generator to avoid loading entire file, and attempts to work around undecodable dir/file name prints. """
用户5760343
2022/05/13
1.6K0
scrapy进阶开发(一):scrapy架构源码分析
其子类有HtmlResponse,TextResponse,XmlResponse
Meet相识
2018/09/12
2.5K0
scrapy进阶开发(一):scrapy架构源码分析
tf.train.Coordinator
任何线程都可以调用coord.request_stop()来请求所有线程停止。为了配合请求,每个线程必须定期检查coord .should_stop()。一旦调用了coord.request_stop(), coord.should_stop()将返回True。 一个典型的线程运行协调器会做如下事情:
狼啸风云
2019/06/13
1.6K0
python gui中线程的调用
""" ################################################################################# System-wide thread interface utilities for GUIs.
用户5760343
2022/05/13
3770
一篇文章带你搞定Python中logging模块
日志是什么?这个不用多解释。百分之九十的程序都需要提供日志功能。Python内置的logging模块,为我们提供了现成的高效好用的日志解决方案。但是,不是所有的场景都需要使用logging模块,
Go进阶者
2021/11/19
4390
一篇文章带你搞定Python中logging模块
点击加载更多

相似问题

反应-本机:挠曲盒对齐

24

右对齐反应本机挠曲盒

32

挠曲盒高度在反应本机

10

挠曲盒响应导航问题

10

图像内响应挠曲盒问题

30
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文