WebClient Bot - Многопоточность - PullRequest
1 голос
/ 22 апреля 2011

Я делаю бота для онлайн-игры.Это работает, но это однопоточное приложение.

Я хочу сделать его многопоточным приложением.Я знаю, как работает фоновый работник.

Для всех своих задач я использую один веб-клиент с добавленной поддержкой Cookie.

Моему, например, нужно открыть одну страницу, подождать 10 минут и выполнить следующую инструкцию.Я также хочу иметь возможность остановить бот в любое время.

Нужно ли передавать мой объект WebClient фоновому рабочему для работы?Каков наилучший способ обновить элементы управления в моей форме?

У меня есть один класс, в котором есть все значения, которые я хочу отобразить в главной форме.Должен ли я запускать какое-либо событие при изменении свойства?Если да, можете ли вы привести мне пример?


ОБНОВЛЕНИЕ:

Это мой специальный веб-клиент:

using System;
using System.Net;

namespace Game_Bot
{
    class WebClientEx : WebClient
    {
        public CookieContainer CookieContainer { get; private set; }

        public WebClientEx()
        {
            CookieContainer = new CookieContainer();
        }

        public void ClearCookies()
        {
            CookieContainer = new CookieContainer();
        }

        protected override WebRequest GetWebRequest(Uri address)
        {

            var request = base.GetWebRequest(address);
            if (request is HttpWebRequest)
            {
                (request as HttpWebRequest).CookieContainer = CookieContainer;
            }
            return request;
        }
    }

}

Это хорошо?способ обновления пользовательского интерфейса?Или есть какая-нибудь бетаер?

    public void SetStatus(string status)
    {
        if (TransferLeftLabel.Dispatcher.Thread == Thread.CurrentThread)
        {
            TransferLeftLabel.Text = status;
        }
        else
        {
            TransferLeftLabel.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
            (Action)(() => {  SetStatus(string status); }));
        }
    }

1 Ответ

3 голосов
/ 22 апреля 2011

Вот как бы я это сделал:

Первый: Мне нравится управлять потоками вручную вместо использования элемента управления BackgroundWorker при создании многопоточных приложений, подобных тому, которое вы хотите изменить.

Чтобы начать новую тему, это просто:

public void SomeMethod() {
    var thread = new Thread(MyMethod);
    thread.Start(); //Will start the method
}

public void MyMethod() {
    //Do whatever you want inside the thread here
}

Вы можете получить столько экземпляров Thread, сколько захотите, сохранить их в списке и управлять тем, как предпочитаете. Однако это не правда, что чем больше потоков, тем лучше. Поиск в Google.

Об открытии страниц и хранении файлов cookie.

Я думаю, что у вас может быть экземпляр класса в вашей Форме или где у вас есть логика (в каком-то месте, к которому могут обращаться потоки), (назовем это WebUtils) с помощью метода, подобного: GoToUrl(<url here>) или что-то в этом роде и CookieCollection как поле в этом классе для хранения файлов cookie.

То, что вы должны принять во внимание:

При вызове GoToUrl может потребоваться блокировка при доступе к переменной cookie, чтобы избежать несоответствия.

Об обновлении элементов управления:

Вы можете создать событие внутри класса WebUtils, и каждый раз, когда к странице обращаются, вы можете запустить это событие. Перед запуском потоков вы должны подписаться на событие в Form, вы можете сделать что-то похожее с lock при обновлении / доступе / изменении элементов управления в вашей форме.

Теперь, как избежать сообщения Control ____ accessed from a thread other than the thread it was created...?

Вот пример:

Если вы хотите изменить свойство Text элемента управления textBox1, вместо того, чтобы просто выполнить:

textBox1.Text = "Ey, I accessed the site

вы можете сделать:

MethodInvoker m = () => { textBox1.Text = "Ey, I accessed the site" };
if (InvokeRequired)
    BeginInvoke(m);
else
    m.Invoke()

Убедитесь, что все модификации сделаны так.

Это всего лишь обзор. Я не специалист по ниткам.
Вот хорошая ссылка на потоки в целом: Threading в C #

Edit:
Посмотрите на свойство потоков IsBackground. Это может быть причиной зависания приложения, если вы просто хотите его использовать.

Я предложил создать класс WebUtils, или как вы хотите его назвать, потому что так я его создал в прошлом.

Что-то вроде:

public class WebUtils {
    CookieContainer _cookies;

    public WebUtils() {
        _cookies = new CookieContainer();
    }

    public void AccessPage(string url) {
        //Here I create a new instance of a HttpWebRequest class, and assign `_cookies` to its `Cookie` property.
        //Don't really know if `WebClient` has something similar
    }   
}
...