Very Slow to pass “large” amount of data from Chro

2019-01-20 05:17发布

I am using Chrome's Native Messaging API to pass the DOM of a page to my host. When I try passing a small string from my extension to my host, everything works, but when I try to pass the entire DOM (which isn't that large...only around 260KB), everything runs much slower and I eventually get a Native host has exited error preventing the host from responding.

My main question: Why does it take so long to pass a 250KB - 350KB message from the extension to the host?

According to the developer's site:

Chrome starts each native messaging host in a separate process and communicates with it using standard input (stdin) and standard output (stdout). The same format is used to send messages in both directions: each message is serialized using JSON, UTF-8 encoded and is preceded with 32-bit message length in native byte order. The maximum size of a single message from the native messaging host is 1 MB, mainly to protect Chrome from misbehaving native applications. The maximum size of the message sent to the native messaging host is 4 GB.

The page's whose DOMs I'm interested in sending to my host are no more than 260KB (and on occasion 300KB), well below the 4GB imposed maximum.

popup.js

document.addEventListener('DOMContentLoaded', function() {
    var downloadButton = document.getElementById('download_button');
    downloadButton.addEventListener('click', function() {
        chrome.tabs.query({currentWindow: true, active: true}, function (tabs) {
            chrome.tabs.executeScript(tabs[0].id, {file: "getDOM.js"}, function (data) {
                chrome.runtime.sendNativeMessage('com.google.example', {"text":data[0]}, function (response) {
                    if (chrome.runtime.lastError) {
                        console.log("Error: " + chrome.runtime.lastError.message);
                    } else {
                        console.log("Response: " + response);
                    }
                });
            });
        });
    });
});

host.exe

private static string StandardOutputStreamIn() {
    Stream stdin = new Console.OpenStandardInput();
    int length = 0;
    byte[] bytes = new byte[4];
    stdin.Read(bytes, 0, 4);
    length = System.BitConverter.ToInt32(bytes, 0);

    string = "";
    for (int i=0; i < length; i++)
        string += (char)stdin.ReadByte();

    return string;
}

Please note, I found the above method from this question.

For the moment, I'm just trying to write the string to a .txt file:

public void Main(String[] args) {
    string msg = OpenStandardStreamIn();
    System.IO.File.WriteAllText(@"path_to_file.txt", msg);
}
  1. Writing the string to the file takes a long time (~4 seconds, and sometimes up to 10 seconds).
  2. The amount of text that is actually written varies, but it's never more than just the top document declaration and a few IE comment tags. All the text now shows up.
  3. This file with barely any text is 649KB but the actual document should only 205KB (when I download it). The file is still slightly larger than it should be (216KB when it should be 205KB).

I've tested my getDOM.js function by just downloading the file, and the entire process is almost instantaneous.

I'm not sure why this process is taking such a long time, why the file is so huge, or why barely any of the message is actually being sent.

I'm not sure if this has something to do with deserializing the message in a specific way, if I should create a port instead of using the chrome.runtime.sendNativeMessage(...); method, or if there's something else entirely that I'm missing.

All help is very much appreciated! Thank you!


EDIT

Although my message is correctly sending FROM the extension TO the host, I am now receiving a Native host has exited error before the extension receive's the host's message.

1条回答
劫难
2楼-- · 2019-01-20 05:33

This question is essentially asking, "How can I efficiently and quickly read information from the standard input?"

In the above code, the problem is not between the Chrome extension and the host, but rather between the standard input and the method that reads from the standard input stream, namely StandardOutputStreamIn().

The way the method works in the OP's code is that a loop runs through the standard input stream and continuously concatenates the input string with a new string (i.e. the character it reads from the byte stream). This is an expensive operation, and we can get around this by creating a StreamReader object to just grab the entire stream at once (especially since we know the length information contained in the first 4 bytes). So, we fix the speed issue with:

    public static string OpenStandardStreamIn()
    {
        //Read 4 bytes of length information
        System.IO.Stream stdin = Console.OpenStandardInput();
        int length = 0;
        byte[] bytes = new byte[4];
        stdin.Read(bytes, 0, 4);
        length = System.BitConverter.ToInt32(bytes, 0);

        char[] buffer = new char[length];
        using (System.IO.StreamReader sr = new System.IO.StreamReader(stdin))
        {
            while (sr.Peek() >= 0)
            {
                sr.Read(buffer, 0, buffer.Length);
            }
        }

        string input = new string(buffer);

        return input;
    }

While this fixes the speed problem, I am unsure why the extension is throwing a Native host has exited error.

查看更多
登录 后发表回答