P2pServer.pas
上传用户:zhanghw123
上传日期:2021-11-15
资源大小:312k
文件大小:11k
源码类别:

P2P编程

开发平台:

Delphi

  1. Unit P2PServer;
  2. Interface
  3. Uses
  4.   Windows, Messages, SysUtils, Classes,
  5.   StdCtrls, IniFiles,
  6.   P2pConst, P2pCommon,
  7.   IdUDPServer, IdSocketHandle,
  8.   NMUDP;
  9. Type
  10.   TP2PServer = Class;
  11.   {检查存活的线程}
  12.   TCheckLivingThread = Class(TThread)
  13.   Public
  14.     CheckTime: Cardinal;
  15.     Server: TP2PServer;
  16.     Procedure Execute; Override;
  17.     Constructor Create(IStop: boolean; IServer: TP2PServer);
  18.   End;
  19.   TP2PServer = Class
  20.   Private
  21.     P2pLog: TMemo;
  22.     FUserId: Cardinal;
  23.     FBindings: TIDSocketHandles;
  24.     Function GetUserId: Cardinal;
  25.     Procedure SetBindings(Value: TIDSocketHandles);
  26.   Protected
  27.     Procedure Log(Const LogStr: String);
  28.     Procedure OnUDPRead(Sender: TObject; AData: TStream; ABinding: TIdSocketHandle);
  29.     Procedure OnP2pLogin(Data: Pointer; ABinding: TP2pBinding);
  30.     Procedure OnP2pLoginOut(Data: Pointer; ABinding: TP2pBinding);
  31.     Procedure OnP2pWantDoor(Data: Pointer; ABinding: TP2pBinding);
  32.     Procedure OnP2pDoorOpened(Data: Pointer; ABinding: TP2pBinding);
  33.     Procedure OnP2pAnyLifeing(Data: Pointer; ABinding: TP2pBinding);
  34.     //广播事件
  35.     Procedure GiveAllUserNewUser(IUser: TObject);
  36.     Procedure GiveAllUserLeaveUser(IUser: TObject);
  37.     // 发送事件
  38.     Procedure GiveUserList(IUser: TObject);
  39.     Procedure DisUserConn(IUser: TObject);
  40.     Property UserID: Cardinal Read GetUserId;
  41.   Public
  42.     UserList: THashedStringList; {用户列表}
  43.     UDPSocket: TIdUDPServer;
  44.     CheckLive: TCheckLivingThread; {检查线程}
  45.     Constructor Create(Logs: TMemo); Overload;
  46.     Destructor Destroy; Override;
  47.     Function StartServer: boolean;
  48.     Function StopServer: boolean;
  49.     Property Bindings: TIDSocketHandles Read FBindings Write SetBindings;
  50.   End;
  51. Implementation
  52. { TCheckLivingThread }
  53. Constructor TCheckLivingThread.Create(IStop: boolean; IServer: TP2PServer);
  54. Begin
  55.   Inherited Create(IStop);
  56.   Server := IServer;
  57.   FreeOnTerminate := True;
  58.   CheckTime := GetTickCount;
  59. End;
  60. Procedure TCheckLivingThread.Execute;
  61. Var
  62.   i: Integer;
  63. Begin
  64.   While Not Terminated Do
  65.   Begin
  66.     If GetTickCount - CheckTime > 60 * 1000 Then
  67.     Begin
  68.       For i := 0 To Server.UserList.Count - 1 Do
  69.       Begin // Iterate
  70.         Try
  71.           If Not Terminated Then
  72.           Begin
  73.             If abs(GetTickCount - TP2pUser(Server.UserList.Objects[i]).MMCfg.LastLiveTime) > abs(TP2pUser(Server.UserList.Objects[i]).MMCfg.Livinginv) Then
  74.             Begin
  75.               TP2pUser(Server.UserList.Objects[i]).MMCfg.LastLiveTime := GetTickCount;
  76.               TP2pUser(Server.UserList.Objects[i]).MMCfg.LifePoint := TP2pUser(Server.UserList.Objects[i]).MMCfg.LifePoint - 1;
  77.               If TP2pUser(Server.UserList.Objects[i]).MMCfg.LifePoint = 0 Then
  78.                 Server.DisUserConn(Server.UserList.Objects[i]);
  79.             End;
  80.           End;
  81.         Except
  82.           Continue;
  83.         End;
  84.       End; // for
  85.       CheckTime := GetTickCount;
  86.     End
  87.     Else
  88.       Sleep(300);
  89.   End; // while
  90. End;
  91. {P2pServer}
  92. Constructor TP2PServer.Create(Logs: TMemo);
  93. Begin
  94.   P2pLog := Logs;
  95.   UDPSocket := TIdUDPServer.Create(Nil);
  96.   FBindings := UDPSocket.Bindings;
  97. End;
  98. Destructor TP2PServer.Destroy;
  99. Begin
  100.   If UDPSocket.Active Then StopServer;
  101.   If UDPSocket <> Nil Then FreeAndNil(UDPSocket);
  102.   Inherited;
  103. End;
  104. {启动服务器}
  105. Function TP2PServer.StartServer: boolean;
  106. Begin
  107.   Result := false;
  108.   If UDPSocket.Active Then Exit;
  109.   Log('正在启动服务...');
  110.   FUserId := 0;
  111.   UDPSocket.OnUDPRead := OnUDPRead;
  112.   Try
  113.     UDPSocket.Active := True;
  114.     UserList := THashedStringList.Create;
  115.     CheckLive := TCheckLivingThread.Create(false, Self);
  116.     Log('服务启动成功.');
  117.     Result := True;
  118.   Except
  119.     Log('服务启动失败.');
  120.     Exit;
  121.   End;
  122. End;
  123. {停止服务器}
  124. Function TP2PServer.StopServer: boolean;
  125. Var
  126.   i: Integer;
  127. Begin
  128.   Result := false;
  129.   Try
  130.     If Not UDPSocket.Active Then Exit;
  131.     CheckLive.Terminate;
  132.     WaitForSingleObject(CheckLive.Handle, 500);
  133.     If UserList <> Nil Then
  134.     Begin
  135.       For i := 0 To UserList.Count - 1 Do
  136.         UserList.Objects[i].Free;
  137.       FreeAndNil(UserList);
  138.     End;
  139.     UDPSocket.Active := false;
  140.     Log('服务停止成功.');
  141.     Result := True;
  142.   Except
  143.     Log('服务停止失败.');
  144.     Exit;
  145.   End;
  146. End;
  147. Procedure TP2PServer.SetBindings(Value: TIDSocketHandles);
  148. Begin
  149.   UDPSocket.Bindings := Value;
  150.   FBindings := Value;
  151. End;
  152. {超时退出}
  153. Procedure TP2PServer.DisUserConn(IUser: TObject);
  154. Var
  155.   Idx: Integer;
  156. Begin
  157.   Log(Format('用户%s超时断开系统.', [TP2pUser(IUser).Address]));
  158.   Idx := UserList.IndexOf(Format('%d', [TP2pUser(IUser).ID]));
  159.   If Idx < 0 Then Exit;
  160.   GiveAllUserLeaveUser(UserList.Objects[Idx]); {广播用户退出}
  161.   UserList.Objects[Idx].Free;
  162.   UserList.Delete(Idx);
  163. End;
  164. Function TP2PServer.GetUserId: Cardinal;
  165. Begin
  166.   Inc(FUserId);
  167.   Result := FUserId;
  168. End;
  169. {日志事件}
  170. Procedure TP2PServer.Log(Const LogStr: String);
  171. Begin
  172.   P2pLog.Lines.Add(Format('%s %s', [FormatDateTime('YYYY-MM-DD HH:NN:SS', Now), LogStr]));
  173.   SendMessage(P2pLog.Handle, EM_SCROLLCARET, 0, 0);
  174. End;
  175. Procedure TP2PServer.OnUDPRead(Sender: TObject; AData: TStream; ABinding: TIdSocketHandle);
  176. Var
  177.   Ptr: Pointer;
  178.   i: Integer;
  179.   Binding: TP2pBinding;
  180. Begin
  181.   Try
  182.     Ptr := TMemoryStream(AData).Memory;
  183.     i := PInt(Ptr)^;
  184.     Binding.PeerIP := ABinding.PeerIP;
  185.     Binding.PeerPort := ABinding.PeerPort;
  186.     Log(Format('接收到用户命令:<%d>.', [i]));
  187.     Case i Of
  188.       P2pLogin: OnP2pLogin(Ptr, Binding); //登陆服务器
  189.       P2pLoginOut: OnP2pLoginOut(Ptr, Binding); //退出服务器
  190.       P2pWantDoor: OnP2pWantDoor(Ptr, Binding); //用户请求开门
  191.       P2pDoorOpened: OnP2pDoorOpened(Ptr, Binding); //用户通知门已经打开了
  192.       P2pAnyLifeing: OnP2pAnyLifeing(Ptr, Binding); //发送心跳包
  193.     End;
  194.   Except
  195.     On e: Exception Do
  196.       Log(Format('处理用户数据时异常原因<Class%s -> %s>', [e.ClassName, e.Message]));
  197.   End;
  198. End;
  199. {登陆服务器}
  200. Procedure TP2PServer.OnP2pLogin(Data: Pointer; ABinding: TP2pBinding);
  201. Var
  202.   Rlb: TResutLoginBack;
  203.   User: TP2pUser;
  204. Begin
  205.   Log(Format('来自%s:%d的用户发起登陆信息.', [ABinding.PeerIP, ABinding.PeerPort]));
  206.   Rlb.ID.ID := P2pResultLoginBack;
  207.   User := TP2pUser.Create(ABinding);
  208.   User.ID := UserID;
  209.   Rlb.UserID := User.ID;
  210.   Log(Format('用户[%d]登陆成功.', [User.ID]));
  211.   User.Call := PLoginUser(Data)^.Name;
  212.   Rlb.State := 1;
  213.   Rlb.Addr := Format('%s:%d', [ABinding.PeerIP, ABinding.PeerPort]);
  214.   User.Socket.SendBuffer(Rlb, SizeOf(Rlb)); // 返回登陆成功
  215.   GiveAllUserNewUser(User); // 广播新用户加入(不包括自己)
  216.   GiveUserList(User); // 给用户列表
  217.   UserList.AddObject(Format('%d', [User.ID]), User);
  218. End;
  219. {退出服务器}
  220. Procedure TP2PServer.OnP2pLoginOut(Data: Pointer; ABinding: TP2pBinding);
  221. Var
  222.   Idx: Integer;
  223. Begin
  224.   Idx := UserList.IndexOf(IntToStr(PLoginoutUser(Data)^.UserID));
  225.   If Idx < 0 Then Exit;
  226.   Log(Format('用户%s退出系统.', [TP2pUser(UserList.Objects[Idx]).Address]));
  227.   GiveAllUserLeaveUser(UserList.Objects[Idx]); {广播用户退出}
  228.   UserList.Objects[Idx].Free;
  229.   UserList.Delete(Idx);
  230. End;
  231. {请求开门}
  232. Procedure TP2PServer.OnP2pWantDoor(Data: Pointer; ABinding: TP2pBinding);
  233. Var
  234.   Source, Dest: Cardinal;
  235.   Idx: Integer;
  236.   SUser, DUser: TP2pUser;
  237.   WD: TWantDoor;
  238. Begin
  239.   Source := PWantDoor(Data)^.SourceID;
  240.   Idx := UserList.IndexOf(Format('%d', [Source]));
  241.   If Idx < 0 Then Exit;
  242.   SUser := TP2pUser(UserList.Objects[Idx]);
  243.   Dest := PWantDoor(Data)^.DestID;
  244.   Idx := UserList.IndexOf(IntToStr(Dest));
  245.   If Idx = -1 Then Exit;
  246.   DUser := TP2pUser(UserList.Objects[Idx]);
  247.   Log(Format('用户%s申请P2P目标%s', [SUser.Address, DUser.Address]));
  248.   WD.ID.ID := P2pSomeOneWantDoor;
  249.   WD.SourceID := Source;
  250.   DUser.Socket.SendBuffer(WD, SizeOf(WD));
  251. End;
  252. {门开了}
  253. Procedure TP2PServer.OnP2pDoorOpened(Data: Pointer; ABinding: TP2pBinding);
  254. Var
  255.   Idx: Integer;
  256.   WD: TWantDoor;
  257. Begin
  258.   Idx := UserList.IndexOf(IntToStr(PWantDoor(Data)^.DestID));
  259.   If Idx < 0 Then Exit;
  260.   WD.ID.ID := P2pDoneDoor;
  261.   Log(Format('用户%d已经为%s打开门.', [PWantDoor(Data)^.SourceID, TP2pUser(UserList.Objects[Idx]).Address]));
  262.   WD.DestID := PWantDoor(Data)^.SourceID;
  263.   TP2pUser(UserList.Objects[Idx]).Socket.SendBuffer(WD, SizeOf(WD));
  264. End;
  265. {心跳}
  266. Procedure TP2PServer.OnP2pAnyLifeing(Data: Pointer; ABinding: TP2pBinding);
  267. Var
  268.   Idx: Integer;
  269.   L: TLiving;
  270. Begin
  271.   Idx := UserList.IndexOf(Format('%d', [PLiving(Data)^.SourceUserId]));
  272.   If Idx < 0 Then Exit;
  273.   Log(Format('接收到%s:%d发过来的心跳包 名称:%s', [ABinding.PeerIP, ABinding.PeerPort, TP2pUser(UserList.Objects[Idx]).Address]));
  274.   TP2pUser(UserList.Objects[Idx]).MMCfg.LifePoint := 2;
  275.   TP2pUser(UserList.Objects[Idx]).MMCfg.LastLiveTime := GetTickCount;
  276.   //回答心跳
  277.   L.ID.ID := P2pAnyToAntLifeing;
  278.   L.SourceUserId := 0;
  279.   TP2pUser(UserList.Objects[Idx]).Socket.SendBuffer(L, SizeOf(L));
  280. End;
  281. {广播有新用户进入}
  282. Procedure TP2PServer.GiveAllUserNewUser(IUser: TObject);
  283. Var
  284.   i: Integer;
  285.   NewUser: TNewUser;
  286. Begin
  287.   With NewUser Do
  288.   Begin
  289.     ID.ID := P2PALLNewUser;
  290.     Ip := TP2pUser(IUser).Binding.PeerIP;
  291.     Port := TP2pUser(IUser).Binding.PeerPort;
  292.     Call := TP2pUser(IUser).Call;
  293.     UserID := TP2pUser(IUser).ID;
  294.     For i := 0 To UserList.Count - 1 Do
  295.       TP2pUser(UserList.Objects[i]).Socket.SendBuffer(NewUser, SizeOf(NewUser));
  296.   End;
  297. End;
  298. {广播有用户离开}
  299. Procedure TP2PServer.GiveAllUserLeaveUser(IUser: TObject);
  300. Var
  301.   i: Integer;
  302.   NewUser: TLoginoutUser;
  303. Begin
  304.   NewUser.ID.ID := P2PALLLeaveUser;
  305.   NewUser.UserID := TP2pUser(IUser).ID;
  306.   For i := 0 To UserList.Count - 1 Do
  307.     TP2pUser(UserList.Objects[i]).Socket.SendBuffer(NewUser, SizeOf(NewUser));
  308. End;
  309. {发送所有列表}
  310. Procedure TP2PServer.GiveUserList(IUser: TObject);
  311. Var
  312.   i: Integer;
  313.   MS: TMemoryStream;
  314.   Head: Thead;
  315.   Count: Word;
  316.   Len: Word;
  317.   Item: String;
  318. Begin
  319.   Log(Format('向用户%s发送用户列表.', [TP2pUser(IUser).Address]));
  320.   MS := TMemoryStream.Create;
  321.   Try
  322.     Head.ID := P2PGiveUserlist;
  323.     Count := UserList.Count;
  324.     For i := 0 To Count - 1 Do
  325.     Begin
  326.       If i + 1 < Count Then
  327.         Item := Format('%s%s:%d:%s' + #$D#$A, [Item, TP2pUser(UserList.Objects[i]).Address, TP2pUser(UserList.Objects[i]).ID, TP2pUser(UserList.Objects[i]).Call])
  328.       Else
  329.         Item := Format('%s%s:%d:%s', [Item, TP2pUser(UserList.Objects[i]).Address, TP2pUser(UserList.Objects[i]).ID, TP2pUser(UserList.Objects[i]).Call])
  330.     End;
  331.     Len := Length(Item);
  332.     MS.SetSize(SizeOf(Head) + SizeOf(Count) + Len);
  333.     MS.WriteBuffer(Head, SizeOf(Head));
  334.     MS.WriteBuffer(Count, SizeOf(Count));
  335.     MS.WriteBuffer(Len, SizeOf(Len));
  336.     MS.WriteBuffer(Pointer(Item)^, Len);
  337.     TP2pUser(IUser).Socket.SendStream(MS);
  338.   Finally
  339.     MS.Free;
  340.   End;
  341. End;
  342. End.