delphi Udp 통신
6954 단어 delphi 프로그래밍
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 IsLink Time Out: Boolean;End; var frmUDPServer : TfrmUDPServer; UdpList : TMsObjectList;//이 클래스는 개인이 다시 쓰는 Tstringlist 클래스입니다.
심박수.로그인메시지를 전달하다.{$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 ('데이터 길이' + 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.