首页 > 解决方案 > 在 Delphi 中使用 UDP 服务器

问题描述

我有一个使用 Delphi 7 制作的项目。使用 Delphi XE7 编译时出现错误。项目中使用了 Indy 组件套件。我认为问题是由于 Indy 9 和 Indy 10 之间的差异造成的。我尝试了很多方法来解决问题,但都没有成功。我怎么解决这个问题?

procedure TRealTimeForm.btnListenClick(Sender: TObject);
begin
  try
   FUDPServer.DefaultPort := StrToInt(edtPort.Text);
   FUDPServer.OnUDPRead:=UDPServerUDPRead;
   FUDPServer.Active := True;
   btnListen.Enabled := False;
 except
   on E:Exception do
    ShowMessage(e.Message);
 end;
end;

procedure TRealTimeForm.UDPServerUDPRead(Sender: TObject; AData: TStream;
  ABinding: TIdSocketHandle);
var
  i: integer;
  lReceiveData: array of Byte;
  sDIN: string;
  year,month,day,hour,minute,second: integer;
  rec: IRecordExt;
  iInt64: Int64;
begin
{
  [0-7]: for check data valid, you can ignore.
[8-23]: these 16 bytes are what you want is the Log entity. The structure is:
Size of structure: 16 bytes
Structure:
//
  UINT64    UserID      //8 bytes
//
  UINT32  Year    :  7;  //7 bits, MAX: 127, base on 2000.
  UINT32  Month  :  4;  //4 bits
  UINT32  Day    :  5;  //5 bits
  UINT32  Action  :  4;    //4 bits
  UINT32  Status  :  5;  //5 bits
  UINT32  JobCode  :  7;  //7 bits, MAX: 127
  UINT32  Antipassback  :1;  //1 bit
  UINT32  DeviceID:  14;  //14 bits, MAX: 16383
  UINT32  Hour  :  5;  //5 bits
  UINT32  Minute  :  6;  //6 bits
  UINT32  Second  :  6;  //6 bits
//
//
[24-31]: device physical address.
}
  try
    if AData.Size < GLogLen then
    begin
      SetLength(lReceiveData,AData.Size);
      AData.ReadBuffer(lReceiveData[0],AData.Size);
      ShowDataLog(lReceiveData);
      Exit;
    end;
    SetLength(lReceiveData,GLogLen);
    AData.ReadBuffer(lReceiveData[0],GLogLen);
    ShowDataLog(lReceiveData);
    if not IsCorectGLog(lReceiveData) then
      Exit;
    rec := CoRecordExt.Create;

    iInt64 := 0;
    for i := 8 to 15 do
    begin
      iInt64 := iInt64 + lReceiveData[i] shl ((i-8) * 8);
    end;
    sDIN := IntToStr(iInt64);
    year := lReceiveData[16] and $7F + 2000;
    month := ((lReceiveData[16] + lReceiveData[17] shl 8) shr 7) and $0F;
    day := (lReceiveData[17] + lReceiveData[18] shl 8) shr 3 and $1F;
    hour := (lReceiveData[21] + lReceiveData[22] shl 8) shr 7 and $1F;
    minute := (lReceiveData[22] + lReceiveData[23] shl 8) shr 4 and $3F;
    second := lReceiveData[23] shr 2 and $3F;

    rec.DIN := sDIN;
    rec.Clock := EncodeDate(year,month,day) + EncodeTime(hour,minute,second,0);
    rec.Verify := (lReceiveData[18] + lReceiveData[19] shl 8) shr 4 and $1F;
    rec.Action := lReceiveData[18] and $0F;
    rec.DN := (lReceiveData[20] + lReceiveData[21] shl 8 + lReceiveData[22] shl 16) shr 1 and $3FFF;
    AddRecord(rec);
    FUDPServer.SendBuffer(ABinding.PeerIP,ABinding.PeerPort,lReceiveData[0],GLogLen);
  except
    on E: Exception do
    begin
      mmoDataLog.Lines.Add(e.Message);
    end;
  end;
end;

给出错误的部分:

FUDPServer.OnUDPRead:=UDPServerUDPRead;
FUDPServer.SendBuffer(ABinding.PeerIP,ABinding.PeerPort,lReceiveData[0],GLogLen);

标签: delphiudpindy

解决方案


在 Indy 10 中,OnUDPRead事件的签名和SendBuffer()方法都发生了变化。如果您查看新声明,您会很容易看到这一点。

此外,在 Indy 9 和 10 中,您应该使用提供给您的对象的SendTo()方法将响应发送回发送者,而不是使用服务器集合中 的第一个方法,这可能是也可能不是在多宿主系统中发送的正确套接字。TIdSocketHandleOnUDPReadSendBuffer()TIdUDPServerTIdSocketHandleBindings

试试这个:

procedure TRealTimeForm.btnListenClick(Sender: TObject);
begin
  try
    FUDPServer.DefaultPort := StrToInt(edtPort.Text);
    FUDPServer.OnUDPRead := UDPServerUDPRead;
    FUDPServer.Active := True;
    btnListen.Enabled := False;
  except
    on E: Exception do
      ShowMessage(e.Message);
  end;
end;

procedure TRealTimeForm.UDPServerUDPRead(AThread: TIdUDPListenerThread;
  const AData: TIdBytes; ABinding: TIdSocketHandle);
var
  i: integer;
  sDIN: string;
  year, month, day, hour, minute, second: Integer;
  rec: IRecordExt;
  iInt64: Int64;
begin
{
  [0-7]: for check data valid, you can ignore.
[8-23]: these 16 bytes are what you want is the Log entity. The structure is:
Size of structure: 16 bytes
Structure:
//
  UINT64    UserID      //8 bytes
//
  UINT32  Year    :  7;  //7 bits, MAX: 127, base on 2000.
  UINT32  Month  :  4;  //4 bits
  UINT32  Day    :  5;  //5 bits
  UINT32  Action  :  4;    //4 bits
  UINT32  Status  :  5;  //5 bits
  UINT32  JobCode  :  7;  //7 bits, MAX: 127
  UINT32  Antipassback  :1;  //1 bit
  UINT32  DeviceID:  14;  //14 bits, MAX: 16383
  UINT32  Hour  :  5;  //5 bits
  UINT32  Minute  :  6;  //6 bits
  UINT32  Second  :  6;  //6 bits
//
//
[24-31]: device physical address.
}
  try
    if Length(AData) < GLogLen then
    begin
      ShowDataLog(AData);
      Exit;
    end;

    ShowDataLog(AData);
    if not IsCorectGLog(AData) then
      Exit;

    rec := CoRecordExt.Create;

    iInt64 := 0;
    for i := 8 to 15 do
    begin
      iInt64 := iInt64 + AData[i] shl ((i-8) * 8);
    end;
    sDIN := IntToStr(iInt64);
    year := AData[16] and $7F + 2000;
    month := ((AData[16] + AData[17] shl 8) shr 7) and $0F;
    day := (AData[17] + AData[18] shl 8) shr 3 and $1F;
    hour := (AData[21] + AData[22] shl 8) shr 7 and $1F;
    minute := (AData[22] + AData[23] shl 8) shr 4 and $3F;
    second := AData[23] shr 2 and $3F;

    rec.DIN := sDIN;
    rec.Clock := EncodeDateTime(year, month, day, hour, minute, second,. 0);
    rec.Verify := (AData[18] + AData[19] shl 8) shr 4 and $1F;
    rec.Action := AData[18] and $0F;
    rec.DN := (AData[20] + AData[21] shl 8 + AData[22] shl 16) shr 1 and $3FFF;
    AddRecord(rec);
    ABinding.SendTo(ABinding.PeerIP, ABinding.PeerPort, AData, 0, GLogLen);
  except
    on E: Exception do
    begin
      mmoDataLog.Lines.Add(e.Message);
    end;
  end;
end;

推荐阅读