【问题标题】:Sending Screen using Delphi (Implementing VNC client / Server)使用 Delphi 发送屏幕(实现 VNC 客户端/服务器)
【发布时间】:2019-08-05 21:14:44
【问题描述】:

几周前一直在阅读 Indy 的一些文档。使用 Indy,我已经能够为简单程序实现客户端和服务器程序,因此我想测试自己的 VNC 程序,比如 teamviewer,开始使用 Indy,我确实喜欢这个主题而不是使用 Raw winsock,Indy 确实帮助了我,但是我确实有一个问题想换掉。 我正在编写类似于我自己的 teamviewer 的代码,它需要客户端和服务器现在我想从服务器获取屏幕截图并发送到客户端

在客户端我做了一些看起来像这样的连接

procedure TForm1.FormCreate(Sender: TObject);
begin
IdTCPServer1:=TIdTCPServer.Create(nil);
IdTCPServer1.DefaultPort:=50000;
IdTCPServer1.OnExecute:=IdTCPServer1Execute;
IdTCPServer1.Active:=true;
end;

现在 onExecute 看起来像这样来抓取屏幕截图并发送给 Indy (Winsock)

procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
mem_dc : HDC;
bmp : TBitmap;
_bm : BITMAP;
w, h : Integer;
dimensions : Integer;
begin
    bmp := TBitmap.Create;
    GetObject (bm, sizeof (BITMAP), @_bm);
    w := _bm.bmWidth;
    h := _bm.bmHeight;
    bmp.Height := h;
    bmp.Width := w;
    mem_dc := CreateCompatibleDC (bmp.Canvas.Handle);
    SelectObject (mem_dc, bm);
    BitBlt (bmp.Canvas.Handle,0, 0, w, h, mem_dc, 0, 0, SRCCOPY);
    Canvas.Draw (0, 0, bmp);
    DeleteObject (mem_dc);
    bmp.Free;

    //Send Dimensions vis Indy here 
    dimensions := w * h / 4;
    while True do
    begin
        AContext.Connection.IOHandler.WriteLn(dimensions);
        // and do same for Pixels
    end;
end.

由于我是这样的新手,我只是获取宽度和高度并发送还是我必须使用类似这样的东西单独发送它们:

procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
mem_dc : HDC;
bmp : TBitmap;
_bm : BITMAP;
w, h : Integer;
begin
    bmp := TBitmap.Create;
    GetObject (bm, sizeof (BITMAP), @_bm);
    w := _bm.bmWidth;
    h := _bm.bmHeight;
    bmp.Height := h;
    bmp.Width := w;
    mem_dc := CreateCompatibleDC (bmp.Canvas.Handle);
    SelectObject (mem_dc, bm);
    BitBlt (bmp.Canvas.Handle,0, 0, w, h, mem_dc, 0, 0, SRCCOPY);
    Canvas.Draw (0, 0, bmp);
    DeleteObject (mem_dc);
    bmp.Free;

    //Send Dimensions vis Indy here 
    dimensions := w * h;
    while True do
    begin
        AContext.Connection.IOHandler.WriteLn(w);
        AContext.Connection.IOHandler.WriteLn(h);
        // Then add the same for Pixels
    end;
end.

【问题讨论】:

    标签: delphi vnc


    【解决方案1】:

    有很多不同的方法可以做到这一点,所以不可能确切地说出你应该应该做什么。例如,如果您查看它发送标头和数据的 HTTP 协议,标头描述了随后的数据。因此,标头会说明有多少数据,或者可能如何确定有多少数据(如分块编码)。其他协议(例如 OSI X25)在带有二进制编码标头的已定义消息中发送信息。

    设计通信协议可能具有挑战性,但也很有收获。

    我建议您考虑要在每个方向发送多少种不同类型的数据。然后考虑一下您将来可能想要发送更多。

    您可能希望应用程序同时与多个客户端进行通信,因此请考虑如何识别对方的每个“会话”。对于收到的每条消息,您希望能够首先确定数据是什么,然后对其进行处理。您可以使用基于文本的标头(更易于调试),例如 HTTP,或者您可以使用已定义的结构,将预定义的值作为二进制数据传输(更紧凑)。

    我通常希望收到的每条消息都有一个标题,其中包含:

    会话 ID(允许一个程序服务多个连接) 数据类型 数据类型相关信息(根据类型不同的数据项数量) 内容长度

    后面是内容。您可以将内容和标题保留在一封邮件中,并尽量让邮件保持简短。

    您可能会发现将屏幕截图分解为已定义的部分更容易。这也意味着,如果您将当前屏幕截图与上一个屏幕截图进行比较,您只需将更改发送到屏幕布局即可。因此,当您发送零件时,您需要同时提供要发送的零件的大小及其位置。

    一旦你有一些基本的工作,如果你设计了一个灵活的信息交换协议,你可以用各种方式扩展它。

    【讨论】:

    • 感谢您的回答,基本上我想要实现的是一个简单的屏幕共享应用程序,我可以在工作中使用它,比如说我想在办公室做一些项目,我正在休假例如,我可以在主服务器上运行应用程序,回家并直接从家里控制 PC。这就是屏​​幕共享应用程序,它基本上使用 RFB(远程帧缓冲区)协议来共享屏幕,仅此而已。
    • @Roy - 好的,那么你需要实现 RFB 协议。你的问题没有具体提到。查看协议定义,然后编写实现它的代码。我将您的问题解释为有关实现通信协议的一般编码问题。
    • 这就是我的意思,所以我在问我是否得到了由第一个来源中的东西分配的尺寸,我做了尺寸:= w * h / 4;或者像第二个例子一样,我后来在网上看到了一些东西,经过深度搜索codepad.co/snippet/delphi-small-vnc-server-using-indy-comps
    • 所以我的想法是,服务器发送宽度 * 高度 / 4,接收方得到它(recv)并显示在 Picturebox 中,希望我这里没有遗漏任何东西
    • RFB 有一个 RFC,并且有很多可用的实现。这意味着您可以针对其他版本测试您的版本,以检查它们是否按预期工作,这是个好消息。如果您以前没有进行过任何网络编程,那么像 Wireshark 这样的工具会很有帮助 - 它可以让您查看交换的信息,如果您遇到问题,您可以将您所做的与其他实现所做的进行比较。祝你好运!
    猜你喜欢
    • 2012-11-09
    • 2018-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-06
    • 2020-06-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多