竹达彩奈cos小樱:服务器开发

来源:百度文库 编辑:偶看新闻 时间:2024/05/07 16:37:03

服务器开发

总结了一些经验,现贴出于大家讨论。
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连接同步管理我稍后放上来,欢迎大家讨论。   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)); //?T?Tμè
    If Terminated Then Exit;
    If hQueue.Count <= 0 Then Exit;
    mQueueItem := hQueue.Pop;
    mQueueItem.rThreadTag := hTag;
    mQueueItem.rIsError := False;
    CoInitialize(Nil);
    If Assigned(mQueueItem.rADOQuery) Then
    Begin
      Try
        mQueueItem.rADOQuery.Connection := hADOConnect;
        If mQueueItem.rIsCommand Then
          mQueueItem.rADOQuery.ExecSQL
        Else
          mQueueItem.rADOQuery.Open;
      Except
        On E: Exception Do
        Begin
          mQueueItem.rIsError := True;
          mQueueItem.rMessage := E.Message;
        End;
      End;
    End;
    CoUninitialize;
    SetEvent(mQueueItem^.rEvent);
  End;
End;

//***********************************************************TSyncConnect*************************

Var
  FQueueThread: Array[0..csMaxQueueThread] Of TQueueThread;

Constructor TSyncConnect.Create(Const aQueueName: String; Const aConnectStr: String; Const aBuffer: Integer = 1024; Const aThreadCount: Integer = 5);
Var
  i: Integer;
Begin
  Inherited Create;
  InitializeCriticalSection(FLock);
  FQueue := TObjectQueue.Create;
  FSyncManage := TSyncManage.Create(aQueueName, 0, aBuffer);
  If aThreadCount - 1 > csMaxQueueThread Then FThreadCount := csMaxQueueThread Else FThreadCount := aThreadCount - 1;
  For i := 0 To FThreadCount Do
    FQueueThread[i] := TQueueThread.Create(aConnectStr, i, FQueue, FSyncManage);
End;

Destructor TSyncConnect.Destroy;
Var
  i: Integer;
Begin
  EnterCriticalSection(FLock);
  Try
    For i := 0 To FThreadCount Do
    Begin
      FQueueThread[i].Terminate;
      FSyncManage.Release;
      FreeAndNil(FQueueThread[i]);
    End;
    FreeAndNil(FSyncManage);
    FreeAndNil(FQueue);
  Finally
    LeaveCriticalSection(FLock);
    DeleteCriticalSection(FLock);
    Inherited Destroy;
  End;
End;

Procedure TSyncConnect.PushQueue(Var aQueueItem: TQueueItem);
Var
  mQueueItem: PQueueItem;
Begin
  New(mQueueItem);
  mQueueItem^ := aQueueItem;
  mQueueItem^.rEvent := CreateEvent(Nil, False, False, Nil);
  EnterCriticalSection(FLock);
  FQueue.Push(mQueueItem);
  LeaveCriticalSection(FLock);
  FSyncManage.Release;
  WaitForSingleObject(mQueueItem^.rEvent, 60000);
  ResetEvent(mQueueItem^.rEvent);
  CloseHandle(mQueueItem^.rEvent);
  aQueueItem := mQueueItem^;
  Dispose(mQueueItem);
End;

End.    下面是两个队列类的代码,高手帮忙指点指点看看有什么不对的地方,
第一个是限制容量的QUEUE,第二个是标准链表实现的QUEUE
事件是根据条件编译来决定是否使用的

unit FifoQueue;

interface
uses
  Classes, Sysutils, Windows, Syncobjs;

type
  TCompareQueueItemMethod = function(Item1, Item2: Pointer): Boolean;

  TPointerArray = array of Pointer;

  TItemEvent = procedure(Item: Pointer) of object;

  TFifoQueue = class(TObject)
  private
    FQueueArray: TPointerArray;
    FQueueLock: TCriticalSection;
{$IFNDEF SERVERMODE}
    FOnPushItem: TItemEvent;
    FOnGetItem: TItemEvent;
{$ENDIF}
    FFirstItemIndex, FLastItemIndex: Integer;
    FCount, FCapacity: Integer;
  public
    constructor Create(QueueLength: Integer);
    destructor Destroy; override;
    function PushItem(Item: Pointer): Boolean;
    function GetItem: Pointer;
    //function GetItems(GetNum: Integer): TPointerArray;
    function FindItem(Item: Pointer; method: TCompareQueueItemMethod): Boolean;
    property Count: Integer read FCount;
{$IFNDEF SERVERMODE}
    property OnPushItem: TItemEvent read FOnPushItem write FOnPushItem;
    property OnGetItem: TItemEvent read FOnGetItem write FOnGetItem;
{$ENDIF}
  end;

  PLinkNode = ^TLinkNode;
  TLinkNode = record
    Prior: PLinkNode;
    Data: Pointer;
    Next: PLinkNode;
  end;

  TExtendQueue = class(TObject)
  private
    FFirstNode, FLastNode: PLinkNode;
{$IFNDEF SERVERMODE}
    FOnPushItem: TItemEvent;
    FOnPopItem: TItemEvent;
{$ENDIF}
    FCount: Integer;
    procedure DeleteNode(node: PLinkNode);
    procedure Clear;
  public
    constructor Create;
    destructor Destroy; override;
    procedure PushItem(Item: Pointer);
    function PopItem: Pointer;
    function GetItem: Pointer;
    function FindItem(Item: Pointer; method: TCompareQueueItemMethod): Boolean;
    function PopFindItem(Item: Pointer; method: TCompareQueueItemMethod): Pointer;
    property Count: Integer read FCount;
{$IFNDEF SERVERMODE}
    property OnPushItem: TItemEvent read FOnPushItem write FOnPushItem;
    property OnPopItem: TItemEvent read FOnPopItem write FOnPopItem;
{$ENDIF}
  end;

implementation

{ TFifoQueue }

constructor TFifoQueue.Create(QueueLength: Integer);
begin
  FCapacity := QueueLength;
  SetLength(FQueueArray, FCapacity);
  FQueueLock := TCriticalSection.Create;
  FFirstItemIndex := -1;
  FLastItemIndex := -1;
  FCount := 0;
end;

destructor TFifoQueue.Destroy;
begin
  FQueueLock.Free;
  FQueueArray := nil;
end;

function TFifoQueue.FindItem(Item: Pointer; method:
  TCompareQueueItemMethod): Boolean;
var
  i: Integer;
begin
  Result := False;
  if FCount = 0 then Exit;
  FQueueLock.Enter;
  try
    for i := FFirstItemIndex to FLastItemIndex do
      if method(Item, FQueueArray[i]) then
      begin
        Result := True;
        Break;
      end;
  finally
    FQueueLock.Leave;
  end;
end;

function TFifoQueue.GetItem: Pointer;
begin
  Result := nil;
  if FCount = 0 then
    Exit;
  FQueueLock.Enter;
  try
    Result := FQueueArray[FFirstItemIndex];
    Dec(FCount);
    if FCount = 0 then
    begin
      FFirstItemIndex := -1;
      FLastItemIndex := -1;
    end
    else
    begin
      if FFirstItemIndex = FCapacity - 1 then
        FFirstItemIndex := 0
      else
        Inc(FFirstItemIndex);
      if FCount = 1 then
        FLastItemIndex := FFirstItemIndex;
    end;
{$IFNDEF SERVERMODE}
    if Assigned(FOnGetItem) then
      FOnGetItem(Result);
{$ENDIF}
  finally
    FQueueLock.Leave;
  end;
end;

{function TFifoQueue.GetItems(GetNum: Integer): TPointerArray;
var
  ResultNum: Integer;
begin
  ResultNum := Min(GetNum, FCount);
  SetLength(Result, ResultNum);
  FQueueLock.Enter;
  try
    if FFirstItemIndex < FCapacity - 1 then
      FFirstItemIndex := ResultNum - 1
    else
      Inc(FFirstItemIndex, ResultNum);
    Dec(FCount, ResultNum);
    Move(FQueueArray[FFirstItemIndex]);
  finally
    FQueueLock.Leave;
  end;
end;}

function TFifoQueue.PushItem(Item: Pointer): Boolean;
begin
  Result := False;
  if FCount = FCapacity then
    Exit;
  FQueueLock.Enter;
  try
    if FLastItemIndex = FCapacity - 1 then
      FLastItemIndex := 0
    else
      Inc(FLastItemIndex);
    Inc(FCount);
    if FCount = 1 then
      FFirstItemIndex := FLastItemIndex;
    FQueueArray[FLastItemIndex] := Item;
    Result := True;
{$IFNDEF SERVERMODE}
    if Assigned(FOnPushItem) then
      FOnPushItem(Item);
{$ENDIF}
  finally
    FQueueLock.Leave;
  end;
end;

{ TExtendQueue }

procedure TExtendQueue.Clear;
var
  tmp, node: PLinkNode;
begin
  node := FFirstNode;
  while Assigned(node) do
  begin
    tmp := node;
    node := node^.Next;
    Dispose(tmp);
  end;
end;

constructor TExtendQueue.Create;
begin
  FCount := 0;
  FFirstNode := nil;
end;

destructor TExtendQueue.Destroy;
begin
  Clear;
  inherited;
end;

function TExtendQueue.FindItem(Item: Pointer;
  method: TCompareQueueItemMethod): Boolean;
var
  node: PLinkNode;
begin
  Result := False;
  if FCount = 0 then
    Exit
  else
  begin
    node := FFirstNode;
    while Assigned(node) do
    begin
      Result := method(Item, node.Data);
      if Result then
        Break;
      node := node^.Next;
    end;
  end;
end;

function TExtendQueue.PopFindItem(Item: Pointer;
  method: TCompareQueueItemMethod): Pointer;
var
  node: PLinkNode;
begin
  Result := nil;
  if FCount = 0 then
    Exit
  else
  begin
    node := FFirstNode;
    while Assigned(node) do
    begin
      if method(Item, node.Data) then
      begin
        Result := node.Data;
        DeleteNode(node);
        Dec(FCount);
{$IFNDEF SERVERMODE}
        if Assigned(FOnPopItem) then
          FOnPopItem(Result);
{$ENDIF}
        Break;
      end;
      node := node^.Next;
    end;
  end;
end;

function TExtendQueue.GetItem: Pointer;
begin
  if FCount = 0 then
    Result := nil
  else
    Result := FFirstNode^.Data;
end;

procedure TExtendQueue.DeleteNode(node: PLinkNode);
begin
  if Assigned(node^.Prior) then
    node^.Prior^.Next := node^.Next;
  if Assigned(node^.Next) then
    node^.Next^.Prior := node^.Prior;
  if FCount = 1 then
  begin
    FFirstNode := nil;
    FLastNode := nil;
  end
  else
  begin
    if node = FFirstNode then
      FFirstNode := node^.Next;
    if node = FLastNode then
      FLastNode := node^.Prior;
  end;
  Dispose(node);
end;

function TExtendQueue.PopItem: Pointer;
var
  node: PLinkNode;
begin
  if FCount = 0 then
    Result := nil
  else
  begin
    node := FFirstNode;
    Result := node^.Data;
    if FCount = 1 then
    begin
      FLastNode := nil;
      FFirstNode := nil;
    end
    else
    begin
      FFirstNode := node^.Next;
      FFirstNode.Prior := nil;
    end;
    Dec(FCount);
{$IFNDEF SERVERMODE}
  if Assigned(FOnPopItem) then
    FOnPopItem(Result);
{$ENDIF}
    Dispose(node);
  end;
end;

procedure TExtendQueue.PushItem(Item: Pointer);
var
  node: PLinkNode;
begin
  if FCount = 0 then
  begin
    New(FFirstNode);
    FFirstNode^.Data := Item;
    FFirstNode^.Next := nil;
    FFirstNode^.Prior := nil;
    FLastNode := FFirstNode;
  end
  else
  begin
    New(node);
    node^.Data := Item;
    node^.Next := nil;
    node^.Prior := FLastNode;
    FLastNode^.Next := node;
    FLastNode := node;
  end;
  Inc(FCount);
{$IFNDEF SERVERMODE}
  if Assigned(FOnPushItem) then
    FOnPushItem(Item);
{$ENDIF}
end;

end.

  
开发服务器的项目 怎样开发电子邮件接收服务器 web开发中的ftp服务器? 邮件服务器开发需要解决的问题 如何利用VB进行SOAP服务器和客户端开发 做J2EE开发用什么应用服务器比较方便? FTP服务器软件名称及其开发公司的名称 什么是监控服务器,监控服务器的作用有哪些?一般应用开发中是怎么用监控服务器的? 作为J2EE的集成开发环境和服务器,请说说WebSphere有哪些特点? 不安装整个php服务器,能写代码、debug的php开发环境是什么? 请问如果要开发一个服务器-客户端的聊天软件,周期是多少? 网站开发非常之旅 服务器配置全攻略 那有免费下的? 求<asp.net服务器控件开发技术与实例>光盘源码 VFP开发扩充为局域网内的客户/服务器共享版,请各位高手指点迷津? 中文环境下开发的ASP+ACCESS网站在国内服务器上正常 2003下开发的asp.net程序移到2000服务器下可以运行吧? JSP开发的网站对于服务器的要求是不是比ASP.net的要求高? 我要帮某公司做一个JSP网站,带数据库开发、域名申请、部署到服务器上,该开价多少? 求ASP.NET服务器控件开发技术与实例一书源码 topweb520@126.com 谢谢了 服务器--- 开发一款网络游戏(如劲舞团等)并投入测试所需要的投入大概是多少?包括服务器等硬件。 谁有没有提供软件下载,电影下载的FTP服务器地址给一个用户名未开发与密码吧,有匿名的最好多谢了 谁有没有提供软件下载,电影下载的FTP服务器地址给一个用户名未开发与密码吧,有匿名的最好多谢了 我在安装.NET2003之前被告知先要安装web服务开发的组件(FrontPage服务器扩展)谁知道这组件如何安装,谢谢