delphi Udp通信

unit MainUnit;

interface

uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, IdBaseComponent, IdComponent, IdUDPBase,
IdUDPServer, IdSystatUDPServer, IdGlobal, IdSocketHandle, Vcl.StdCtrls,
IdUDPClient, Vcl.ComCtrls,StrUtils,System.Types, Vcl.ExtCtrls, Data.DB,
Data.Win.ADODB,MsListObject,DateUtils;

type
TfrmUDPServer = class(TForm)
udpserver: TIdUDPServer;
mmoData: TMemo;
btnClear: TButton;
lv1: TListView;
tmrheart: TTimer;
qry1: TADOQuery;
btnFree: TButton;
procedure FormCreate(Sender: TObject);
procedure udpserverUDPRead(AThread: TIdUDPListenerThread;
const AData: TIdBytes; ABinding: TIdSocketHandle);
procedure FormDestroy(Sender: TObject);
procedure btnClearClick(Sender: TObject);
procedure tmrheartTimer(Sender: TObject);
procedure btnFreeClick(Sender: TObject);

private
{ Private declarations }
public
{ Public declarations }
procedure AddListView(AName,AIp,APort:string);

end;
type
TUDPList =Class(TObject) //保存客户端对象
fIp : String; //ip
fPort : Integer; //port
fTime : TDateTime; //时间
fName : String; //用户名
fPwd : String; //密码
private

public
procedure UpdateTime; //用于更新客户端的连接时间
{判断是否心跳超时}
function IsLinkTimeOut: Boolean;
End;
var
frmUDPServer : TfrmUDPServer;
UdpList : TMsObjectList; //这个类为个人重写的TStringlist类。

implementation
// 心跳包。登录。消息转发。
{$R *.dfm}
uses IniFiles,DMUnit;
//释放队列对象
procedure TfrmUDPServer.btnFreeClick(Sender: TObject);
begin
UDpList.Destroy;
lv1.Items.Clear;
mmoData.Clear;
UdpList := TMsObjectList.Create;
end;
//清空mmo中的数据 (mmo中保存登陆数据)
procedure TfrmUDPServer.btnClearClick(Sender: TObject);
begin
mmoData.Clear;
end;

procedure TfrmUDPServer.FormCreate(Sender: TObject);
begin
try
//绑定端口
udpServer.DefaultPort := 86;
//激活
udpServer.Active := true;
//创建队列
UdpList := TMsObjectList.Create;
except
on e:exception do
WriteLog(‘绑定端口出错’+e.Message);

end;
end;
//用户登录 此处为了线程安全而做的操作(当多个用户登录时不会出现问题)
function CheckLogin(const UserName,Password: string): Boolean;
begin
Result := dbFindTabelValue(
‘SELECT count(1) as c from tb_user where username =”’+UserName+”’ and password = ”’+Password+”’ ‘,
False,
‘c’
);
end;
//接收客户端发送的信息,这个方法是最重要的
//AThread 为线程对象主要是处理多个客户端发送数据 AData就是客户端所发送的数据
//ABindIng 为Socket对象,里面包含了客户端的登录Ip 与端口
procedure TfrmUDPServer.udpserverUDPRead(AThread: TIdUDPListenerThread;
const AData: TIdBytes; ABinding: TIdSocketHandle);
var
Ip,Port : String; //IP ,Port
Udp,RUdp : TUDPList; //创建用户
SendUdp : TUDPList; //发送语音者
i : Integer;
index : Integer;
Data : TIdBytes;
UserData : String;
ArrayData : TArray;
Name : String;
Pwd : string;
begin
Ip := ABinding.PeerIP;
Port := IntToStr(ABinding.PeerPort);
OutputDebugString(PChar(‘数据长度’+Length(AData).ToString));
writeLog(‘数据长度接收开始’+ IntTOStr( Length(AData)));
//接收数据头,判断是什么操作,这个需要和客户端对好协议
**//此处的数据头为 0 表示登录,后面是用户名与用户密码
//1 表示发送语音消息 2 表示心跳 心跳用于检测客户端是否还存在**
case BytesToInt32(AData) of
0 : begin //登录
AppendBytes(Data,AData,4,Length(AData)-4);
//用户登录信息
UserData := BytesToString(Data,IndyTextEncoding_UTF8);
ArrayData := UserData.Split([‘|’]);

  if Length(ArrayData)>1 then begin
    Name        := ArrayData[0];
    Pwd         := ArrayData[1];
    {验证用户名和密码}
    if CheckLogin(Name,Pwd) then begin

      Udp         := UdpList.IndexOfObject(Ip+Port);
      if Assigned(Udp) and (Udp.fName = Name) then begin
         //登录成功返回数据
        Data := ToBytes(Integer(0));
        udpServer.SendBuffer(Udp.fIp,Udp.fPort,TIdIPVersion.Id_IPv4,Data);
        WriteLog('用户已经存在队列返回0表示登录');
        Udp.UpdateTime;
        Exit;
      end;

      mmoData.Lines.Add('登录用户数据'+UserData);
      Udp         := TUDpList.Create;
      Udp.fIp     := Ip;
      Udp.fPort   := Port.ToInteger;
      Udp.UpdateTime;
      UDP.fName   := Name;
      UDP.fPwd    := Pwd;
      UdpList.AddObject(Ip+Port,Udp);
      AddListView(Name,Ip,Port);
      try
        //登录成功返回数据
        Data := ToBytes(Integer(0));
        udpServer.SendBuffer(Udp.fIp,Udp.fPort,TIdIPVersion.Id_IPv4,Data);
        WriteLog('登录成功'+'IP:'+Udp.fIp +'端口:'+IntTOstr(Udp.fPort));

      except
         on e:exception do
          WriteLog('系统错误'+e.Message);
      end;

    end else begin
      Data := ToBytes(Integer(-1));
      udpServer.SendBuffer(Ip,Port.ToInteger,TIdIPVersion.Id_IPv4,Data);
      writeLog('用户名或者密码错误'+'用户名='+Name+'密码='+Pwd);
      mmoData.Lines.Add('用户名或者密码错误='+'用户名='+Name +'密码=' + Pwd);
    end;

  end;

end;
1: begin  //发送语音
  SendUdp :=UdpList.IndexOfObject(IP+Port);
  if Assigned(SendUdp) = False then begin
    udpServer.SendBuffer(Ip,Port.ToInteger,TIdIPVersion.Id_IPv4,ToBytes(Integer(-1)));
    writeLog('非法用户!'+IP+Port);
    exit;
  end;
  SendUdp.UpdateTime;
  AppendBytes(Data,AData,4,Length(AData)-4);
  for I := 0 to UdpList.Count-1 do begin

    RUdp := UdpList.Objects[i];
    if Assigned(RUdp) then begin

       if (RUdp.fName<>SendUDp.fName) then begin

         udpServer.SendBuffer(RUdp.fIp,RUdp.fPort,TIdIPVersion.Id_IPv4,Data);
         writeLog('发送数据长度'+ IntTOStr( Length(Data)));
         WriteLog('接收语音--'+'用户IP:'+RUdp.fIp+'用户端口:'+IntToStr(RUdp.fPort));
       end else
         WriteLog('发送语音--'+'用户IP:'+RUdp.fIp+'用户端口:'+IntToStr(RUdp.fPort));

    end;
  end;
end;

2: begin  //发送心跳
  SendUdp :=UdpList.IndexOfObject(IP+Port);
  if Assigned(SendUdp) = False then exit;
  SendUdp.UpdateTime;
  Data := ToBytes(Integer(2));
  udpServer.SendBuffer(Ip,Port.ToInteger,TIdIPVersion.Id_IPv4,Data);
  WriteLog('回传心跳数据'+'IP:'+Ip +'端口:'+Port);
end;

end;

end;

procedure TfrmUDPServer.FormDestroy(Sender: TObject);
begin
udpServer.Active := false;
UdpList.Destroy;
end;
//定时器 从队列中删除客户端对象
procedure TfrmUDPServer.tmrheartTimer(Sender: TObject);
var
I : integer;
begin
UdpList.Lock;
try
for I := UdpList.Count -1 downto 0 do
if UdpList.Objects[I].IsLinkTimeOut then begin
UdpList.FreeAndNilObject(I);
end;
finally
UdpList.UnLock;
end;

end;

//添加用户登录数据在TListView列表中
procedure TfrmUDPServer.AddListView(AName,AIp,APort:string);
var
item : TListItem;
begin
item := lv1.Items.Add;
item.Caption := AName;
item.SubItems.Add(AIP);
item.SubItems.Add(APort);
item.SubItems.Add(FormatDateTime(‘c’,Now))
end;

{ TUDPList }
//此方法用于判断心跳数据超过10分钟都没有接收到了,此时删除用户
function TUDPList.IsLinkTimeOut: Boolean;
begin
Result := MinutesBetween(Now,fTime) > 10;
end;
//每次用户发送数据都更新最新时间
procedure TUDPList.UpdateTime;
begin
fTime := Now;
end;

end.

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值