C # Закрытие / сбой сервера, если клиент подключается к нему, когда сервер потерял фокус (например, работает заставка) - PullRequest
3 голосов
/ 05 декабря 2011

Я пишу клиент-серверное приложение, используя TCP-сокеты. Сервер написан на C # с использованием Visual Studio 2010 (.NET 4.0). Сервер допускает несколько клиентских подключений одновременно, поэтому я использую Async. стиль. Сервер должен подключаться к базе данных (MySQL), и пока запущена серверная программа, мне нужно взаимодействовать с базой данных. По этой причине я использую BackgroundWorker для запуска бесконечного цикла прослушивания (который будет принимать клиентов), чтобы предотвратить зависание интерфейса и возможность доступа к базе данных из визуального интерфейса.

Все работает нормально, кроме случаев, когда программа сервера теряет фокус. Примеры потери фокуса: на компьютере, на котором запущена серверная программа, запускается заставка, вы нажимаете на часы на панели задач, чтобы увидеть время, вы открываете другую вдову (проводник окон, калькулятор ...). Если серверная программа теряет фокус и клиент пытается подключиться, сервер полностью закрывается! Если я запускаю сервер из Visual Studio, он не выдает никаких ошибок или исключений. Если у меня запущенная версия сервера, Microsoft Windows покажет диалоговое окно «Программирование не отвечает ...».

Вот как структурирован мой код:

Переменные в основном классе:

const int portNo  = 12345;
static System.Net.IPAddress localAdd = System.Net.IPAddress.Parse("192.168.1.67");
static TcpListener tcpListenerReadWrite  = new TcpListener(localAdd, portNo);

В основной форме кнопка запускает сервер:

private void button1_Click(object sender, EventArgs e)
{
    tcpListenerReadWrite.Start();
    backgroundWorker1.RunWorkerAsync();
}

Фоновая рабочая функция DoWork:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    while (true)
    {
        ChatClient clientRead = new ChatClient(tcpListenerReadWrite.AcceptTcpClient());
    }
}

В классе сервера конструктор выглядит следующим образом:

public ChatClient(TcpClient client) //constructor
{
    _client = client;
    _clientIP = client.Client.RemoteEndPoint.ToString();

    //start reading data from the client in a separate thread
    data = new byte[_client.ReceiveBufferSize];
    _client.GetStream().BeginRead(data, 0, Convert.ToInt32(_client.ReceiveBufferSize), ReceiveMessage, client);
}

При получении сообщения сервером:

public void ReceiveMessage(IAsyncResult asyncResult)
{
    //read received message from client
}

Два заключительных замечания: (1) когда клиент подключается к серверу, первое, что он делает, - отправляет сообщение на сервер как сообщение Hello, (2) перед записью сервера в визуальном интерфейсе, в котором я тестировал его Консольный режим и этой проблемы не было, заставка запускалась и ничего не происходило. Конечно, в режиме консоли я не использовал BackgroundWorker.

Есть идеи, почему сервер падает?

Ответы [ 2 ]

2 голосов
/ 05 декабря 2011

Имеет ли это какое-либо отношение к созданию TcpListener в основном потоке пользовательского интерфейса, а не в вашем фоновом потоке?Вы сами сказали, что этого не происходит в консольном приложении.Я подозреваю, что, поскольку у вас есть некоторые элементы пользовательского интерфейса, это не так ясно.

Я предлагаю переместить ALL вашей сети за пределы потока пользовательского интерфейса, а не в "основной" класс.Имейте это полностью независимым.

1 голос
/ 01 января 2012

Я нашел причину сбоя моего сервера (это заняло у меня некоторое время, потому что в последнее время я сосредоточился на программировании клиента, это сегодня, когда я вернулся к программированию сервера).Как предположил @ Moo-Juice, это проблема, связанная с доступом к пользовательскому интерфейсу.Фактически вот сценарий, который вызывал сбой:

  1. Сервер запускается
  2. Он входит в бесконечный цикл, прослушивая подключения клиентов.Этот бесконечный цикл находится в backgroundWorker.
  3. . Клиент подключается к серверу.
  4. Я печатаю сообщение на textBox, которое подключил клиент. // здесь проблема
  5. Чтобы установить точку (4), я использую метод backgroundWorker.ReportProgress.

Чтобы рассмотреть проблему,сбой сервера только , если фокус не на программе (например, работает заставка), но сбой не происходит, если фокус на программе и ведение журнала работает.Когда я остановил запись, все пошло хорошо.Так что знайте, я знаю источник проблемы, но я не знаю, почему она вызывает сбой;насколько я знаю, ReportProgress предназначен для того, чтобы сообщать о прогрессе пользовательскому интерфейсу.В любом случае, я постараюсь решить это сейчас, особенно потому, что знаю, куда идти.На случай, если вам интересно посмотреть, как я веду запись в журнал, используйте функцию, которую я использовал:

private void PrintString(string stringToPrint)
{
    var myForm = Form1.ActiveForm as Form1;
    myForm.backgroundWorker1.ReportProgress(1, stringToPrint);
}

А вот функция ReportProgress:

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    textBox1.Text += (string)e.UserState;
    textBox1.Text += Environment.NewLine;
}

Ничего такогонеобычно, но достаточно, чтобы вызвать у меня головную боль :) Спасибо за вашу помощь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...