利用完成端口开发的服务端,其整体程序如下:
unit Servermanage;
    //对通信的管理
interface
  uses
  SysUtils, Classes,Variants, IOCPComp, SyncObjs, comms,Messages;Type  TServerManage=Class
    private
      FLock: TCriticalSection;  //锁定标志
      FServerSocket: TServerSocket;  //服务      FServerActive: Boolean;  //服务激活标志    protected
      function OnClientRead(ASocket: TCustomSocket; AData: Pointer;
        ACount: Integer): Integer;
      procedure OnClientError(ASocket: TCustomSocket; ErrorEvent: TErrorEvent;
        var ErrCode: Integer);
      procedure OnClientEvent(ASocket: TCustomSocket;
          SocketEvent: TSocketEvent);
      procedure SetServerActive(const Value: Boolean);      function GetLoginCount:Integer;//返回登录的总计人数
    public
       procedure initPort;
       procedure StartServer;
       procedure StopServer;
       procedure RefreshServer;//刷新服务       constructor Create(AOwner: TComponent);
       destructor Destroy; override;    published
       property ServerActive:Boolean read FServerActive write SetServerActive;       Property LoginCount:integer read GetLoginCount;  End;
implementation
constructor TServerManage.Create(AOwner: TComponent);
begin
  inherited Create;  FLock := TCriticalSection.Create;  FServerSocket := TServerSocket.Create;
  FServerSocket.OnClientRead := OnClientRead;
end;
destructor TServerManage.Destroy;
begin
   Flock.Free;
   ServerActive := False;
   FServerSocket.Free;  inherited;
end;
function TServerManage.OnClientRead(ASocket: TCustomSocket; AData: Pointer;
  ACount: Integer): Integer;
var
  Buffer:String;
  p:pointer;
  dataBlock:TDataBlock;begin
    SetLength(Buffer,ACount);
    System.Move(Adata^,Buffer[1],ACount);
    //处理完成后的返回消息,不论如何处理,都应该向发报机提供一个返回的消息
    dataBlock.context := 'testtest';
     p := @DataBlock;
     ASocket.Write(p^,255);    //发送返回的消息    Result := 0;end;
end.client端:
procedure TClient.Execute;
var
  p:pointer;
  D: TdataBlock;begin
  try
    StrPCopy(D.Content,Trim(LoginQuery+'|2|2|'+INTTOSTR(CC)));
//    d.Content :=LoginQuery+'|2|2|';
    inc(cc);    FSocket.Open(FHost, FHost, '', DbServerPort);
    P := @d;
    FSocket.SendBuf(P^,length(d.Content));  //读返回的值
    FillChar(D, 255, 0);    FSocket.ReceiveBuf(D.Content, 255);    FrmMain.Caption := D.Content;
          //读完后关闭
  finally
     Fsocket.Close;
   end;
end;现在发现server端的ONClientRead事件执行了两次,请问是什么原因?

解决方案 »

  1.   

    2次,仔细调试了么,每次的ACount是多少?是不是2次的和=length(d.Content)?
      

  2.   

    每次的ACOUNT都一致.第一次传进来的是正确的.
    第二次实际上AData为空了,但它就是要一直触发onclientread.如果把Asocket.write屏掉,就不会一直触发.
      

  3.   

    Client的接收事件里是不是有Sendbuf
      

  4.   

     没有.client中主要是个线程procedure TClient.Execute;
    var
      p:pointer;
      D: TdataBlock;begin
      try
        D.Content := LoginQuery+'|2|2';    FSocket.Open(FHost, FHost, '', DbServerPort);
        P := @d;
        if FSocket.Connected then
        begin      FSocket.SendBuf(P^,length(d.Content));      //读返回的值
          FillChar(D, 255, 0);      FSocket.ReceiveBuf(D.Content, 255);      FrmMain.Caption := D.Content;
              //读完后关闭
              end;
      finally
         Fsocket.Close;
       end;
    end;