P2pClient.pas
资源名称:P2P.rar [点击查看]
上传用户:zhanghw123
上传日期:2021-11-15
资源大小:312k
文件大小:13k
源码类别:
P2P编程
开发平台:
Delphi
- Unit P2pClient;
- Interface
- Uses Windows, SysUtils, Classes,
- Messages, ComCtrls, IniFiles, Graphics,
- P2pConst, P2pCommon,
- NMUDP;
- Type
- TP2pClient = Class
- P2pLog: TRichEdit;
- IsConnToServer: Boolean;
- Public
- ID: Cardinal; //唯一标示
- Addr: String; //自己的名称 PTP时需要
- Socket: TNMUDP;
- UserList: THashedStringList; //用户列表
- MMCfg: TP2pUserConfig;
- Constructor Create(Logs: TRichEdit); Overload;
- Destructor Destroy; Override;
- Procedure Log(Const LogStr: String);
- Procedure LoginServer(ICall: String);
- Procedure LoginOutServer;
- Procedure Living;
- Procedure OnDataRec(Sender: TComponent; NumberBytes: Integer; FromIP: String; Port: Integer);
- Procedure OnLoginBack(Data: Pointer; NumberBytes: Integer; ABinding: TP2pBinding);
- Procedure OnNewUser(Data: Pointer; NumberBytes: Integer; ABinding: TP2pBinding);
- Procedure OnLeaveUser(Data: Pointer; NumberBytes: Integer; ABinding: TP2pBinding);
- Procedure OnUserList(Data: Pointer; NumberBytes: Integer; ABinding: TP2pBinding);
- Procedure OnSomeOneWantDoor(Data: Pointer; NumberBytes: Integer; ABinding: TP2pBinding);
- Procedure OnDoneDoor(Data: Pointer; NumberBytes: Integer; ABinding: TP2pBinding);
- Procedure OnSayHello(Data: Pointer; NumberBytes: Integer; ABinding: TP2pBinding);
- Procedure OnSayHelloResponse(Data: Pointer; NumberBytes: Integer; ABinding: TP2pBinding);
- Procedure OnChat(Data: Pointer; NumberBytes: Integer; ABinding: TP2pBinding);
- Procedure OnWantDoor(IDestUser: TObject);
- Procedure SendChat(IUser: TObject; RichEdit: TRichEdit);
- End;
- Implementation
- Uses CltMain;
- Constructor TP2pClient.Create(Logs: TRichEdit);
- Begin
- P2pLog := Logs;
- Log('创建点对点客户端服务...');
- IsConnToServer := False;
- MMCfg := TP2pUserConfig.Create;
- Socket := TNMUDP.Create(Nil);
- Socket.OnDataReceived := OnDataRec;
- UserList := THashedStringList.Create;
- Log('创建服务器成功.');
- End;
- Destructor TP2pClient.Destroy;
- Var
- i: Integer;
- Begin
- For i := 0 To UserList.Count - 1 Do
- UserList.Objects[i].Free;
- UserList.Free;
- If MMCfg <> Nil Then FreeAndNil(MMCfg);
- If Socket <> Nil Then FreeAndNil(Socket);
- Log('释放服务器成功.');
- Inherited;
- End;
- {日志事件}
- Procedure TP2pClient.Log(Const LogStr: String);
- Begin
- //P2pLog.Font.Color := clBlack;
- //P2pLog.SelAttributes.Color := clred;
- P2pLog.Lines.Add(Format('%s %s', [FormatDateTime('YYYY-MM-DD HH:NN:SS', Now), LogStr]));
- SendMessage(P2pLog.Handle, EM_SCROLLCARET, 0, 0);
- End;
- Procedure TP2pClient.LoginServer(ICall: String);
- Var
- LU: TLoginUser;
- Begin
- Log(Format('向%s:%d发起连接本地使用端口:%d.', [Socket.RemoteHost, Socket.RemotePort, Socket.LocalPort]));
- LU.ID.ID := P2pLogin;
- LU.Name := ICall;
- Socket.SendBuffer(LU, SizeOf(LU));
- End;
- {登出服务}
- Procedure TP2pClient.LoginOutServer;
- Var
- LU: TLoginoutUser;
- Begin
- Log('断开服务.');
- LU.ID.ID := P2pLoginOut;
- LU.UserID := ID;
- Socket.SendBuffer(LU, SizeOf(LU));
- End;
- {发送心跳给服务器}
- Procedure TP2pClient.Living;
- Var
- Llving: TLiving;
- Begin
- Llving.ID.ID := P2pAnyLifeing;
- Llving.SourceUserId := ID;
- Socket.SendBuffer(Llving, SizeOf(Llving));
- MMCfg.LastLiveTime := GetTickCount;
- End;
- Procedure TP2pClient.OnDataRec(Sender: TComponent; NumberBytes: Integer; FromIP: String; Port: Integer);
- Var
- Buf: Pointer;
- Binding: TP2pBinding;
- Begin
- If NumberBytes < 0 Then Exit;
- Buf := GetMemory(NumberBytes);
- Try
- Try
- Socket.ReadBuffer(Buf^, NumberBytes);
- Binding.PeerIP := FromIP;
- Binding.PeerPort := Port;
- Log(Format('接收到命令:<%d>.', [Phead(Buf)^.ID]));
- Case Phead(Buf)^.ID Of
- P2pResultLoginBack: OnLoginBack(Buf, NumberBytes, Binding); {注册返回过程}
- P2PALLNewUser: OnNewUser(Buf, NumberBytes, Binding); {有人进来了}
- P2pALLLeaveUser: OnLeaveUser(Buf, NumberBytes, Binding); {有人离开了}
- P2PGiveUserlist: OnUserList(Buf, NumberBytes, Binding); {获取在线用户列表}
- P2pSomeOneWantDoor: OnSomeOneWantDoor(Buf, NumberBytes, Binding); {给用户请求P2P开门命令}
- P2pDoneDoor: OnDoneDoor(Buf, NumberBytes, Binding); {通知客户端已经打开门了}
- P2pSayHello: OnSayHello(Buf, NumberBytes, Binding); {对方的握手信息}
- P2pSayHelloResponse: OnSayHelloResponse(Buf, NumberBytes, Binding); {收到握手的回复信息}
- P2pChat: OnChat(Buf, NumberBytes, Binding); {收到的聊天信息}
- End;
- Except
- On e: Exception Do
- Log(Format('处理数据时异常原因:<%s->%s>', [e.ClassName, e.Message]));
- End;
- Finally
- FreeMem(Buf, NumberBytes);
- End;
- End;
- {登陆返回过程}
- Procedure TP2pClient.OnLoginBack(Data: Pointer; NumberBytes: Integer; ABinding: TP2pBinding);
- Var
- Rlb: PResutLoginBack;
- Begin
- Rlb := Data;
- If Rlb^.State = 1 Then
- Begin
- IsConnToServer := True;
- Addr := Rlb.Addr;
- ID := Rlb.UserID;
- Log(Format('登陆服务器成功 返回名称:%s,ID:%d.', [Addr, ID]));
- End Else
- Begin
- Log('登陆服务器失败,也许是由于已经登陆导致.');
- IsConnToServer := False;
- End;
- End;
- {有人来了}
- Procedure TP2pClient.OnNewUser(Data: Pointer; NumberBytes: Integer; ABinding: TP2pBinding);
- Var
- User: TP2pUser;
- Obj: TListITem;
- Binding: TP2pBinding;
- Begin
- Log(Format('新用户加入%s:%d.', [PNewUser(Data)^.Ip, PNewUser(Data)^.Port]));
- Binding.PeerIP := PNewUser(Data)^.Ip;
- Binding.PeerPort := PNewUser(Data)^.Port;
- User := TP2pUser.Create(Binding);
- User.ID := PNewUser(Data)^.UserID;
- User.Call := PNewUser(Data)^.Call;
- UserList.AddObject(IntToStr(User.ID), User);
- Obj := FrmMain.UserList.Items.Add;
- With Obj Do
- Begin
- Caption := User.Call;
- Data := User;
- User.ListOwer := TObject(Obj);
- End;
- End;
- {有人离开了}
- Procedure TP2pClient.OnLeaveUser(Data: Pointer; NumberBytes: Integer; ABinding: TP2pBinding);
- Var
- Idx: Integer;
- Begin
- Idx := UserList.IndexOf(Format('%d', [PLoginoutUser(Data)^.UserID]));
- If Idx < 0 Then Exit;
- Log(Format('用户%s离开了.', [TP2pUser(UserList.Objects[Idx]).Address]));
- FrmMain.UserList.Items.Delete(TListITem(TP2pUser(UserList.Objects[Idx]).ListOwer).Index);
- TP2pUser(UserList.Objects[Idx]).Free;
- UserList.Delete(Idx);
- End;
- {接收在线用户列表}
- Procedure TP2pClient.OnUserList(Data: Pointer; NumberBytes: Integer; ABinding: TP2pBinding);
- Procedure GetEveryWord(S: String; e: TStrings; C: String);
- Var
- t, a: String;
- Begin
- t := S;
- While Pos(C, t) > 0 Do
- Begin
- a := Copy(t, 1, Pos(C, t) - 1);
- t := Copy(t, Pos(C, t) + 1, Length(t) - Pos(C, t));
- e.Add(a);
- End;
- If Trim(t) <> '' Then e.Add(t);
- End;
- Var
- User: TP2pUser;
- Binding: TP2pBinding;
- Count, Len: Word;
- Items: String;
- i: Integer;
- List, BaseList: TStrings;
- Obj: TListITem;
- Begin
- Move(Pointer(PChar(Data) + SizeOf(Thead))^, Count, SizeOf(Count));
- Move(Pointer(PChar(Data) + SizeOf(Thead) + SizeOf(Count))^, Len, SizeOf(Len));
- Log(Format('接收在线用户列表共%d个.', [Count]));
- If Count > 0 Then
- Begin
- SetLength(Items, Len);
- Move(Pointer(PChar(Data) + SizeOf(Thead) + SizeOf(Len) + SizeOf(Len))^, PChar(Items)^, Len);
- List := TStringList.Create;
- BaseList := TStringList.Create;
- Try
- BaseList.Text := Items;
- For i := 0 To BaseList.Count - 1 Do
- Begin
- List.Clear;
- GetEveryWord(BaseList.Strings[i], List, ':');
- Binding.PeerIP := List.Strings[0];
- Binding.PeerPort := StrToInt(List.Strings[1]);
- User := TP2pUser.Create(Binding);
- User.ID := StrToInt(List.Strings[2]);
- User.Call := List.Strings[3];
- UserList.AddObject(Format('%d', [User.ID]), User);
- Obj := FrmMain.UserList.Items.Add;
- With Obj Do
- Begin
- Caption := User.Call;
- Data := User;
- User.ListOwer := TObject(Obj);
- End;
- OnWantDoor(User);
- End; {FOR}
- Finally
- BaseList.Free;
- List.Free;
- End;
- End; {IF}
- End;
- {服务器来通知有人敲门}
- Procedure TP2pClient.OnSomeOneWantDoor(Data: Pointer; NumberBytes: Integer; ABinding: TP2pBinding);
- Var
- Idx: Integer;
- OD: TOpenDoor;
- WD: TWantDoor;
- Begin
- Idx := UserList.IndexOf(IntToStr(PWantDoor(Data)^.SourceId));
- If Idx < 0 Then Exit;
- Log(Format('服务端通知%s想和你P2P.', [TP2pUser(UserList.Objects[Idx]).Address]));
- //目标用户存在 给他开门
- OD.ID.ID := P2pOpenDoor;
- TP2pUser(UserList.Objects[Idx]).Socket.SendBuffer(OD, SizeOf(OD));
- Log(Format('已经给%s打开门了.', [TP2pUser(UserList.Objects[Idx]).Address]));
- // 告诉服务器已经打开门了
- WD.ID.ID := P2pDoorOpened;
- WD.SourceId := ID;
- WD.DestID := PWantDoor(Data)^.SourceId;
- Socket.SendBuffer(WD, SizeOf(WD));
- Log(Format('通知服务端已经给%s打开门了.', [TP2pUser(UserList.Objects[Idx]).Address]));
- End;
- {服务器转告申请开门成功 可以握手了}
- Procedure TP2pClient.OnDoneDoor(Data: Pointer; NumberBytes: Integer; ABinding: TP2pBinding);
- Var
- SH: TSayHello;
- Idx: Integer;
- Begin
- Idx := UserList.IndexOf(IntToStr(PWantDoor(Data)^.DestID));
- If Idx < 0 Then Exit;
- Log(Format('服务器通知%s已经把门打开.', [TP2pUser(UserList.Objects[Idx]).Address]));
- // 对方把门打开了 发送握手信息
- SH.ID.ID := P2pSayHello;
- SH.UserID := ID;
- TP2pUser(UserList.Objects[Idx]).Socket.SendBuffer(SH, SizeOf(SH));
- Log(Format('向%S发送握手信息,看对方是否在线.', [TP2pUser(UserList.Objects[Idx]).Address]));
- End;
- {对方的握手信息}
- Procedure TP2pClient.OnSayHello(Data: Pointer; NumberBytes: Integer; ABinding: TP2pBinding);
- Var
- Idx: Integer;
- RH: TSayHello;
- Begin
- Idx := UserList.IndexOf(Format('%d', [PSayHello(Data)^.UserID]));
- If Idx < 0 Then Exit;
- RH.ID.ID := P2pSayHelloResponse;
- RH.UserID := ID;
- TP2pUser(UserList.Objects[Idx]).Socket.SendBuffer(RH, SizeOf(RH));
- Log(Format('接收到用户%S发送的握手信息,给他个回复.', [TP2pUser(UserList.Objects[Idx]).Address]));
- End;
- {用户友好的握手了}
- Procedure TP2pClient.OnSayHelloResponse(Data: Pointer; NumberBytes: Integer; ABinding: TP2pBinding);
- Var
- Idx: Integer;
- Begin
- Idx := UserList.IndexOf(Format('%d', [PSayHello(Data)^.UserID]));
- If Idx < 0 Then Exit;
- Log(Format('%s回复了你的握手信息,成功连接.', [TP2pUser(UserList.Objects[Idx]).Address]));
- End;
- {收到的聊天信息}
- Procedure TP2pClient.OnChat(Data: Pointer; NumberBytes: Integer; ABinding: TP2pBinding);
- Var
- Len: Word;
- Who: Cardinal;
- Idx: Integer;
- Items: String;
- RF: TREFont;
- Begin
- Move(Pointer(PChar(Data) + SizeOf(Thead))^, Len, SizeOf(Len));
- If Len <= 0 Then Exit;
- SetLength(Items, Len);
- Move(Pointer(PChar(Data) + SizeOf(Thead) + SizeOf(Len))^, Who, SizeOf(Who));
- Move(Pointer(PChar(Data) + SizeOf(Thead) + SizeOf(Len) + SizeOf(Who))^, RF, SizeOf(RF));
- Move(Pointer(PChar(Data) + SizeOf(Thead) + SizeOf(Len) + SizeOf(Who) + SizeOf(RF))^, PChar(Items)^, Len);
- With FrmMain.TxtMsg Do
- Begin
- SelAttributes.Color := clBlue;
- Idx := UserList.IndexOf(Format('%d', [Who]));
- If Idx = -1 Then Exit;
- Lines.Add(Format('[%s] [%s]对你说:', [FormatDateTime('YYYY-MM-DD HH:NN:SS', Now), TP2pUser(UserList.Objects[Idx]).Call]));
- SelAttributes.Charset := RF.Charset;
- SelAttributes.Name := RF.Name;
- SelAttributes.Size := RF.Size;
- SelAttributes.Color := RF.Color;
- SelAttributes.Style := RF.Style;
- SelAttributes.Pitch := RF.Pitch;
- Lines.Add(Items + #13#10);
- SendMessage(Handle, EM_SCROLLCARET, 0, 0);
- End;
- End;
- {想与其它用户P2P}
- Procedure TP2pClient.OnWantDoor(IDestUser: TObject);
- Var
- WD: TWantDoor;
- Begin
- Log(Format('向服务端请求PTP 目标:%s.', [TP2pUser(IDestUser).Address]));
- WD.ID.ID := P2pWantDoor;
- WD.SourceId := ID;
- WD.DestID := TP2pUser(IDestUser).ID;
- Socket.SendBuffer(WD, SizeOf(WD));
- End;
- {向对方发送聊天信息}
- Procedure TP2pClient.SendChat(IUser: TObject; RichEdit: TRichEdit);
- Var
- MS: TMemoryStream;
- Head: Thead;
- Who: Cardinal;
- Len: Word;
- RF: TREFont;
- Begin
- With RichEdit Do
- Begin
- Log(Format('向用户%s发送聊天信息<%s>', [TP2pUser(IUser).Address, Text]));
- Head.ID := P2pChat;
- Len := Length(Text);
- RF.Charset := SelAttributes.Charset;
- RF.Name := SelAttributes.Name;
- RF.Size := SelAttributes.Size;
- RF.Color := SelAttributes.Color;
- RF.Style := SelAttributes.Style;
- RF.Pitch := SelAttributes.Pitch;
- End;
- Who := ID;
- MS := TMemoryStream.Create;
- Try
- MS.SetSize(SizeOf(Head) + SizeOf(Who) + SizeOf(RF) + Len);
- MS.WriteBuffer(Head, SizeOf(Head));
- MS.WriteBuffer(Len, SizeOf(Len));
- MS.WriteBuffer(Who, SizeOf(Who));
- MS.WriteBuffer(RF, SizeOf(RF));
- MS.WriteBuffer(Pointer(RichEdit.Text)^, Len);
- TP2pUser(IUser).Socket.SendStream(MS);
- Finally
- MS.Free;
- End;
- End;
- End.