关于用DELPHI开发服务器软件中的一些经验

 

保存 评价 游戏规则 免费注册 关于用DELPHI开发服务器软件中的一些经验 资料下载 关于本站
问题分类 编程问题 非技术题 富翁列表 我的信息 提出问题 在线富翁 富翁日历 笔记列表 我的笔记 写作笔记 全文检索 《专家门诊》

/delphibbs/dispq.asp lid=2342105

富翁名称
富翁密码

请记住我

富翁名称

免费注册



问题:关于用DELPHI开发服务器软件中的一些经验 ( 积分:100, 回复:137, 阅读:6014 )
分类:Internet/TCPIP ( 版主:luyear, robertcool )
来自:element, 时间:2003-12-8 20:52:00, ID:2342105 [显示:小字体 | 大字体]

总结了一些经验,现贴出于大家讨论。
1、构件的使用
   开始我一直使用Indy,但最近在开发一个100-350并发用户的服务器端时发现了Indy问题,由于用户的访问非常繁重,服务器工作两周后出现了70多的废连接。导致服务器响应变的慢。而且我观察到有时INDY能自动释放这些废连接,有时多到200多都不释放。后来我改DXSock 3.0构件,代码没有作任何改动,服务从6月1日到今天没有重启一次而且没有一个废连接,
   我花了一周看DXSock的代码,改了些错误,也学习了很多,DXSock构成思想很好。它的连接响应线程不是动态创建的,而是你设置多少就一次性创建多少。节省了创建、释放的大量时间。
   所以再开发服务器端软件我推进使用DXSOCK构件。

   2、数据库使用
      很多朋友在讨论多线程中使用数据库的问题,这在网络服务器开发中这是常常需要考虑的问题,很多朋友都采用一个线程建立一个数据库的连接,我认为这种方法在小规模、小并发应用中是可以的,但是一旦负荷上去、并发一多这样就很多问题了,比如资源消耗(数据库)、时间消耗。这种方式我用过,结果是运行一段时间后数据库再也连接不上了。
      我再这方面有两个解决办法:
      a、采用ASTA构件的方法,根据分析负荷一次性创建一个ADOCONNEC连接池,靠一个同步模块来管理,客户端请求-》构造SQL-》让同步管理模块来分配一个ADOCONNECT联机-》执行SQL,返回结果,如果这时ADOCONNECT满,此SQL等待。代码如下:
      b、对于不需要实时返回数据库信息的应用,客户端请求来-》服务器创建SQL语句和一个TAG-》SQL语句送入队列,然后一条一条的执行,TAG返回客户端,过一段时间客户端再通过这个TAG来服务端获得结果。
********************************************队列管理代码***********************
Unit uitQueueManage;

Interface

Uses
  Windows,
  Messages,
  SysUtils,
  Variants,
  Classes,
  Contnrs;

Type
  TSyncManage = Class(TObject)
  Protected
    FHandle: THandle;
  Public
    Property Handle: THandle Read FHandle;
    Constructor Create(Const Name: String; InitCount, MaxBuffer: Integer);
    Destructor Destroy; Override;
    Function Release: Boolean; Overload;
    Function WaitFor(TimeOut: Integer): Boolean;
  End;

Type
  PQueueItem = ^TQueueItem;
  TQueueItem = Record
    FRequestCount: Integer;
    FCommand: Integer;
    FDataStr: String;
    FDataInt: Integer;
    FDataBool: Boolean;
  End;
  TProgressEvent = Procedure(Sender: TObject; aQueueItem: TQueueItem) Of Object;
  TQueueManage = Class(TObject)
  Private
    FQueue: TQueue;
    FSyncManage: TSyncManage;
    FOnProgress: TProgressEvent;
    FLock: TRTLCriticalSection;
  Public
    Constructor Create(aQueueName: String; aBuffer: Integer);
    Destructor Destroy; Override;
    Procedure PushQueue(aQueueItem: TQueueItem);
  Published
    Property OnProgress: TProgressEvent Read FOnProgress Write FOnProgress;
  End;

Type
  TQueueThread = Class(TThread)
  Private
    hSyncManage: TSyncManage;
    hOwner: TQueueManage;
    hQueue: TQueue;
    Procedure DoProgress;
  Protected
    Procedure Execute; Override;
  Public
    Constructor Create(aOwner: TQueueManage; aQueue: TQueue; aSyncManage: TSyncManage); Virtual;
  End;

Implementation

//***********************************************************TSyncThread**************************

Constructor TSyncManage.Create(Const Name: String; InitCount, MaxBuffer: Integer);
Begin
  FHandle := CreateSemaphore(Nil, InitCount, MaxBuffer, Pchar(Name));
  If FHandle = 0 Then abort;
End;

Destructor TSyncManage.Destroy;
Begin
  If FHandle <> 0 Then CloseHandle(FHandle);
End;

Function TSyncManage.WaitFor(TimeOut: Integer): Boolean;
Begin
  Result := WaitForSingleObject(FHandle, TimeOut) = WAIT_OBJECT_0;
End;

Function TSyncManage.Release: Boolean;
Begin
  Result := ReleaseSemaphore(FHandle, 1, Nil);
End;

//***********************************************************TQueueThread**************************

Constructor TQueueThread.Create(aOwner: TQueueManage; aQueue: TQueue; aSyncManage: TSyncManage);
Begin
  Inherited Create(True);
  hOwner := aOwner;
  hQueue := aQueue;
  hSyncManage := aSyncManage;
  Priority := tpHigher;
  Resume;
End;

Procedure TQueueThread.Execute;
Begin
  While Not Terminated Do
  Begin
    hSyncManage.WaitFor(Integer(INFINITE)); //无限等
    If Terminated Then Exit;
    DoProgress;
  End;
End;

Procedure TQueueThread.DoProgress;
Var
  mQueueItem: PQueueItem;
Begin
  mQueueItem := hQueue.Pop;
  If Assigned(hOwner.FOnProgress) Then hOwner.FOnProgress(hOwner, mQueueItem^);
  Dispose(mQueueItem);
End;

//***********************************************************TQueueManage*************************

Var
  FQueueThread: TQueueThread;

Constructor TQueueManage.Create(aQueueName: String; aBuffer: Integer);
Begin
  Inherited Create;
  InitializeCriticalSection(FLock);
  FQueue := TObjectQueue.Create;
  FSyncManage := TSyncManage.Create(aQueueName, 0, aBuffer); //缓冲区大小
  FQueueThread := TQueueThread.Create(Self, FQueue, FSyncManage);
End;

Destructor TQueueManage.Destroy;
Begin
  EnterCriticalSection(FLock);
  Try
    FQueueThread.Terminate;
    FSyncManage.Release;
    FreeAndNil(FQueueThread);
    FreeAndNil(FSyncManage);
    FreeAndNil(FQueue);
    Inherited Destroy;
  Finally
    LeaveCriticalSection(FLock);
    DeleteCriticalSection(FLock);
  End;
End;

Procedure TQueueManage.PushQueue(aQueueItem: TQueueItem);
Var
  mQueueItem: PQueueItem;
Begin
  New(mQueueItem);
  mQueueItem^ := aQueueItem;
  EnterCriticalSection(FLock);
  FQueue.Push(mQueueItem);
  LeaveCriticalSection(FLock);
  FSyncManage.Release;
End;

End.
********************************************队列管理代码***********************
ADO连接同步管理我稍后放上来,欢迎大家讨论。  
来自: chenshaizi, 时间:2003-12-8 20:58:00, ID:2342117 学习ing  
来自: guilinxie, 时间:2003-12-8 21:12:00, ID:2342139 这样的贴子很有学习意义。
UP  
来自: fjjb, 时间:2003-12-8 22:03:00, ID:2342226 学习,期待ADO连接同步管理  
来自: tongdanfeng, 时间:2003-12-9 9:16:00, ID:2342528 什么地方有DXSock .30下载 
来自: 唐佐平, 时间:2003-12-9 9:28:00, ID:2342571 很好,谢谢了!  
来自: QSmile, 时间:2003-12-9 9:52:00, ID:2342663 什么地方有DXSock .30下载 

楼主真他妈是个好人。
我选楼主为 2003年大富翁杰出青年  
来自: strgold, 时间:2003-12-9 10:22:00, ID:2342766 kl  
来自: kkg, 时间:2003-12-9 10:46:00, ID:2342839 顶///  
来自: 张无忌, 时间:2003-12-9 12:37:00, ID:2343217 呵呵,200~300个连接压力不够哦,DXSocket也就一般,
 而且DELPHI自己的TQueue类效率很低,我自己改写了一个速度比他快8倍,看来
做服务器程序最好都自己从头写,用现成的始终不是最好的解决方法,而且用别
人的破戒的东西有偷盗之嫌。  
来自: lynu, 时间:2003-12-9 12:45:00, ID:2343250 很不错.
当然大一点的系统,建议还是不要用长连接,这样多数系统能服务的客户端就可以高出很多,一般的系统并发机率可能只有5-15%,我想很少会有系统超过30%以上.不过非长连接的话就要考虑维护会话状态的成本.
indy中大量使用类似如下的代码
  ms := TMemorystream.create;
  ms.write(….)…
这些是很没效率的,如果不为TMemorystream一次性分配足够空间,那么TMemorystream在分配的空间不够用的时候,就需要重新分配,这是一个极没效率的操作.频繁的重新分配,拷贝原数据等,使得TMemorystream在某些时间甚至比硬盘读写都要慢几倍.所以用indy的话就要分析一下系统的实际情况了.

  
来自: element, 时间:2003-12-9 12:47:00, ID:2343256 一切都为了最求快,一切都要自己写,那就失去使用DELPHI的意义了。
服务器实际负荷=并发数*4.3。  
来自: pingshx, 时间:2003-12-9 12:47:00, ID:2343258 楼上的你能否你写的Query给我学习,pingshx@163.com ,THX
楼住能否发你用的DXSocket给我,THX!  
来自: 张无忌, 时间:2003-12-9 12:49:00, ID:2343262 DELPHI一样可以从头来做的,只要你有耐心。  
来自: 张无忌, 时间:2003-12-9 12:51:00, ID:2343268 element:
   你这话我听很多用VC的这么说,他们的意思就是DELPHI只能做一般的普通应用,
难的都要VC做。  
来自: element, 时间:2003-12-9 12:51:00, ID:2343269 ADO连接同步管理代码,我是从应用中剥离出来的,对不起不能提供全部。供大家讨论
Unit uitSyncConnect;

Interface

Uses
  Windows,
  Messages,
  SysUtils,
  Variants,
  Classes,
  Contnrs,
  Activex,
  ADODB,
  DB;

Const
  csMaxQueueThread = 9;

Type
  TSyncManage = Class(TObject)
  Protected
    FHandle: THandle;
  Public
    Property Handle: THandle Read FHandle;
    Constructor Create(Const Name: String; InitCount, MaxBuffer: Integer);
    Destructor Destroy; Override;
    Function Release: Boolean; Overload;
    Function WaitFor(TimeOut: Integer): Boolean;
  End;

Type
  PQueueItem = ^TQueueItem;
  TQueueItem = Record
    rThreadTag: Integer;
    rEvent: THandle;
    rADOQuery: TADOQuery;
    rIsCommand: Boolean;
    rIsError: Boolean;
    rMessage: String[255];
  End;
  TSyncConnect = Class(TObject)
  Private
    FThreadCount: Integer;
    FQueue: TQueue;
    FSyncManage: TSyncManage;
    FLock: TRTLCriticalSection;
  Public
    Constructor Create(Const aQueueName: String; Const aConnectStr: String; Const aBuffer: Integer = 1024; Const aThreadCount: Integer = 5);
    Destructor Destroy; Override;
    Procedure PushQueue(Var aQueueItem: TQueueItem);
  Published

  End;

Type
  TQueueThread = Class(TThread)
  Private
    hSyncManage: TSyncManage;
    hQueue: TQueue;
    hTag: Integer;
    hADOConnect: TADOConnection;
  Protected
    Procedure Execute; Override;
  Public
    Constructor Create(Const aConnStr: String; Const aTag: Integer; aQueue: TQueue; aSyncManage: TSyncManage); Virtual;
    Destructor Destroy; Override;
  End;

Implementation

//***********************************************************TSyncThread**************************

Constructor TSyncManage.Create(Const Name: String; InitCount, MaxBuffer: Integer);
Begin
  FHandle := CreateSemaphore(Nil, InitCount, MaxBuffer, PChar(Name));
  If FHandle = 0 Then abort;
End;

Destructor TSyncManage.Destroy;
Begin
  If FHandle <> 0 Then CloseHandle(FHandle);
End;

Function TSyncManage.WaitFor(TimeOut: Integer): Boolean;
Begin
  Result := WaitForSingleObject(FHandle, TimeOut) = WAIT_OBJECT_0;
End;

Function TSyncManage.Release: Boolean;
Begin
  Result := ReleaseSemaphore(FHandle, 1, Nil);
End;

//***********************************************************TQueueThread**************************

Constructor TQueueThread.Create(Const aConnStr: String; Const aTag: Integer; aQueue: TQueue; aSyncManage: TSyncManage);
Begin
  Inherited Create(True);
  hQueue := aQueue;
  hSyncManage := aSyncManage;
  Priority := tpHigher;
  hADOConnect := TADOConnection.Create(Nil);
  hADOConnect.ConnectionString := aConnStr;
  hTag := aTag;
  Resume;
End;

Destructor TQueueThread.Destroy;
Begin
  Terminate;
  WaitFor;
  FreeAndNil(hADOConnect);
  Inherited Destroy;
End;

Procedure TQueueThread.Execute;
Var
  mQueueItem: PQueueItem;
Begin
  While Not Terminated Do
  Begin
    hSyncManage.WaitFor(Integer(INFINITE)); //μè
    If Terminated Then Exit;
    If hQueue.Count <= 0 Then Exit;
    mQueueItem := hQueue.Pop;
    mQueueItem.rThreadTag := hTag;

来源:only5me

声明:本站部分文章及图片转载于互联网,内容版权归原作者所有,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2008年11月2日
下一篇 2008年11月2日

相关推荐