?? mainunit.pas
字號:
unit MainUnit;
{
P2P方式模擬QQ即時消息通訊
thanksharp@163.com
應(yīng)考慮問題:
1.加入TIMER.定時向好友發(fā)送握手包,以維護網(wǎng)關(guān)NAT的會話SESSION.
}
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, ComCtrls, IdBaseComponent, IdComponent,
IdUDPBase, IdUDPServer, IdSocketHandle, testQQCommon, WinSkinData, AboutUnit;
type
TClient = class(TForm)
Label1: TLabel;
UserNameEdit: TEdit;
Label2: TLabel;
ServerIPEdit: TEdit;
Label3: TLabel;
ServerPortEdit: TEdit;
Panel1: TPanel;
LogonButton: TButton;
LogoutButton: TButton;
Panel2: TPanel;
SendMsgEdit: TRichEdit;
UserList: TListView;
SendMsgButton: TButton;
StatusBar1: TStatusBar;
UDPClient: TIdUDPServer;
RecvEdit: TRichEdit;
CheckBox1: TCheckBox;
P2PTestButton: TButton;
Label4: TLabel;
Button1: TButton;
Button2: TButton;
procedure FormCreate(Sender: TObject);
procedure LogonButtonClick(Sender: TObject);
procedure LogoutButtonClick(Sender: TObject);
procedure UDPClientUDPRead(Sender: TObject; AData: TStream;
ABinding: TIdSocketHandle);
procedure SendMsgButtonClick(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure P2PTestButtonClick(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
MyAccount, ServerIP, MyPublicIP: string;
MyRunPORT, ServerPORT, MyPublicPORT: Integer;
function StartUp(): Boolean;
function CallLogout(): Boolean;
function SendHandData(toIP: string; toPORT: Integer): Boolean;
function ProcRecvLogonData(ThisBinding: TIdSocketHandle; LogonData: TLogonData): boolean;
function ProcRecvLogoutData(ThisBinding: TIdSocketHandle; LogoutData: TLogoutData): boolean;
function ProcRecvFriendData(ThisBinding: TIdSocketHandle; UserData: TUserData): Boolean;
function ProcRecvP2PData(ThisBinding: TIdSocketHandle; HandData: THandData): boolean;
function ProcRecvChatMsgData(ThisBinding: TIdSocketHandle; ChatData: TChatData): boolean;
end;
var
Client: TClient;
AboutBox: TAboutBox;
implementation
{$R *.dfm}
function TClient.StartUp(): Boolean;
var
Listened: Boolean;
ClientPort, MaxPort: Integer;
ASocketHandle: TIdSockethandle;
begin
Listened := false;
ClientPort := CLIENT_PORT;
MaxPort := ClientPort + 10;
Listened := true;
repeat //處理多個程序同時運行的偵聽端口問題
try
UDPClient.DefaultPort := ClientPort;
UDPClient.Active := true;
Listened := true;
break;
except
on EIdCouldNotBindSocket do
begin
UDPClient.Active := false;
UDPClient.Bindings.Clear;
ClientPort := ClientPort + 1;
if ClientPort > MaxPort then
begin
Listened := false;
break;
end;
end;
end;
until not Listened;
if Listened then
begin
MyRunPORT := UDPclient.DefaultPort;
StatusBar1.Panels.Items[1].Text := '運行端口:[' + IntToStr(MyRunPORT) + ']';
Result := true;
end
else
begin
StatusBar1.Panels.Items[1].Text := '偵聽失敗!';
Result := false;
end;
end;
procedure TClient.FormCreate(Sender: TObject);
begin
StartUp();
end;
//登錄上線
procedure TClient.LogonButtonClick(Sender: TObject);
var
LogonDataPackage: TLogonDataPackage;
_ServerIP, _Account: string;
_ServerPORT: Integer;
begin
_ServerIP := ServerIPEdit.Text;
_ServerPORT := StrToInt(ServerPORTEdit.text);
_Account := UserNameEdit.Text;
with LogonDataPackage do
begin
Head.MsgType := IntToStr(LogonSign);
StrPCopy(Body.Account, _Account);
StrPCopy(Body.MyPublicIP, '');
StrPCopy(Body.MyPublicPORT, '');
StrPCopy(Body.lResult, '');
//
end;
UdpClient.SendBuffer(_ServerIP, _ServerPORT, LogonDataPackage, SizeOf(LogonDataPackage));
end;
//注銷下線
procedure TClient.LogoutButtonClick(Sender: TObject);
begin
CallLogout();
end;
//向服務(wù)器注銷
function TClient.CallLogout(): Boolean;
var
LogoutDataPackage: TLogoutDataPackage;
i, _ToPORT: integer;
_toIP: string;
begin
with LogoutDataPackage do
begin
Head.MsgType := IntToStr(LogoutSign);
StrPCopy(Body.Account, MyAccount);
StrPCopy(Body.lResult, '');
end;
UdpClient.SendBuffer(ServerIP, ServerPort, LogoutDataPackage, SizeOf(LogoutDataPackage));
//向好友發(fā)送下線信號
for i := 0 to UserList.Items.Count - 1 do
begin
_ToIP := UserList.Items.Item[i].SubItems[0];
_ToPORT := StrToInt(UserList.Items.Item[i].SubItems[1]);
with LogoutDataPackage do
begin
Head.MsgType := IntToStr(LogoutSign);
StrPCopy(Body.Account, MyAccount);
StrPCopy(Body.lResult, '');
//
end;
UdpClient.SendBuffer(_toIP, _toPORT, LogoutDataPackage, SizeOf(LogoutDataPackage));
Sleep(1);
end;
end;
//UdpClient 讀取數(shù)據(jù)
procedure TClient.UDPClientUDPRead(Sender: TObject; AData: TStream;
ABinding: TIdSocketHandle);
var
_UDPHead: TTQQUDPHead;
_LogonData: TLogonData;
_LogoutData: TLogoutData;
_UserData: TUserData;
_HandData: THandData;
_ChatData: TChatData;
RecvSize, MsgType: integer;
begin
try
MsgType := -1;
RecvSize := adata.Read(_UDPHead, sizeof(_UDPHead)); //接收數(shù)據(jù)頭
MsgType := StrToInt(_UDPHead.MsgType);
if Msgtype = -1 then exit;
//UDPSERVER.Binding.Assign(ABinding); //2005-02-17 Updated!
case MsgType of
LogonSign:
begin
//登錄 <--Server ReBack
Adata.Read(_LogonData, sizeof(TLogonData));
ProcRecvLogonData(Abinding, _LogonData);
end;
LogoutSign:
begin
//注銷 <--Server or Friend
Adata.Read(_LogoutData, sizeof(TLogoutData));
ProcRecvLogoutData(Abinding, _LogoutData);
end;
FriendDataSign:
begin
//收到好友列表信息
Adata.Read(_UserData, sizeof(TUserData));
ProcRecvFriendData(Abinding, _UserData);
end;
HandSign:
begin
//處理P2P請求
Adata.Read(_HandData, sizeof(THandData));
ProcRecvP2PData(Abinding, _HandData);
end;
ChatMsgSign:
begin
//處理聊天消息
Adata.Read(_ChatData, sizeof(TChatData));
ProcRecvChatMsgData(Abinding, _ChatData);
end;
end;
except on E: Exception do
//Memo1.lines.add(E.Message);
end;
end;
//收到登錄服務(wù)器的反饋信息處理
function TClient.ProcRecvLogonData(ThisBinding: TIdSocketHandle; LogonData: TLogonData): boolean;
var
_LogonDataPackage: TLogonDataPackage;
_HandDataPackage: THandDataPackage;
_tempUserBasicInfo: TServerUserBasicInfo;
_Account, _PeerIP, _tempIP, _NeedReBack, _isLogin: string;
i, _PeerPORT, _tempPORT: integer;
begin
_Account := LogonData.Account;
_PeerIP := thisbinding.PeerIP;
_PeerPORT := thisbinding.PeerPort;
_IsLogin := LogonData.lResult;
//登錄成功
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -