Как «повторно использовать» поток? - PullRequest
1 голос
/ 27 февраля 2012

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

Я избавился от использования блоков и сделал переменные-члены для потоков. Теперь моя проблема заключается в том, что когда я вызываю функцию ReadLine в StreamReader на клиенте, она не продолжается до тех пор, пока мое серверное приложение не будет закрыто (или, точнее, до тех пор, пока не будет ликвидирован StreamWriter).

Кажется странным, что мне пришлось бы создавать новый поток (и, соответственно, новый канал, поскольку каждый раз, когда поток закрывается, он также удаляет канал) для каждого сообщения, которое я хочу отправить. Что мне нужно изменить?

Код сервера:

class PipeServer
{
    NamedPipeServerStream _pipeServer;
    StreamWriter _sw;

    public PipeServer(string pipeName)
    {
        _pipeServer = new NamedPipeServerStream(pipeName, PipeDirection.Out);
        _pipeServer.WaitForConnection();
        _sw = new StreamWriter(_pipeServer) { AutoFlush = true };
    }

    public void WriteMessage(string message)
    {
        _sw.WriteLine(message);
    }
}

Код клиента:

public delegate void MessageReadEventHandler(string message);

class PipeClient
{
    public event MessageReadEventHandler MessageReadEvent;

    NamedPipeClientStream _pipeClient;
    StreamReader _sr;

    public PipeClient(string pipeName)
    {
        _pipeClient = new NamedPipeClientStream(".", pipeName, PipeDirection.In);
        _pipeClient.Connect();
        _sr = new StreamReader(_pipeClient);
    }

    public void ReadMessages()
    {
        string temp;

        while ((temp = _sr.ReadLine()) != null)
            if (MessageReadEvent != null)
                MessageReadEvent(temp);
    }
}

Форма сервера содержит одно текстовое поле и имеет следующий код:

public partial class Form1 : Form
{
    PipeClient pClient = new PipeClient("testpipe");

    public Form1() { InitializeComponent(); }

    private void Form1_Load(object sender, EventArgs e)
    {
        pClient.MessageReadEvent += o => { textBox1.Text = o; };
    }

    private void Form1_Shown(object sender, EventArgs e)
    {
        pClient.ReadMessages();
    }
}

Форма клиента имеет одно текстовое поле и имеет следующий код:

public partial class Form1 : Form
{
    PipeServer pServer = new PipeServer("testpipe");

    public Form1() { InitializeComponent(); }

    private void ServerTextBox_TextChanged(object sender, EventArgs e)
    {
        pServer.WriteMessage(ServerTextBox.Text);
    }
}

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

1 Ответ

1 голос
/ 27 февраля 2012

Чтобы дать правильный ответ на ваш вопрос, у меня должен быть SSCCE , с которым я могу бегать и играть.К сожалению, код, который вы разместили, не один.Итак, следующая лучшая вещь, которую я могу сделать, это дать вам указатель на направление, в котором вы должны искать решение своей проблемы: функция NamedPipeServerStream () имеет много перегрузок, некоторые из которых позволяют указывать гораздо больше параметров.Вы должны выбрать одну из этих перегрузок и попытаться указать больше параметров, поигравшись с их значениями, чтобы ваш код заработал.Одним из них, я бы сказал, весьма важным является режим передачи по каналу: байт или сообщение.Попробуйте указать 'message' для этого.

EDIT

Хорошо, я думаю, что вижу две проблемы с опубликованным кодом:

  1. WriteLine (), скорее всего, использует буферизованный ввод / вывод, что означает, что вам придется выполнить много операций WriteLine (), прежде чем буфер заполнится и будет отправлен клиенту.Когда вы завершаете работу сервера, его буфер сбрасывается, поэтому сообщения, используемые для доставки к клиенту в этот момент.

  2. Точно блокирующий цикл ReadLine () на клиенте, вероятно, неразрешите клиенту делать любые перерисовки, поэтому установка текста текстового поля в соответствии с содержанием полученного сообщения, вероятно, не окажет никакого влияния.(Если установка свойства text не вызывает перерисовку, я не уверен, что это произойдет, это не должно быть.) Это можно решить, следуя либо textBox1.Text = o; с textBox1.Update();, либо вставив вызов System.WinForms.Application.DoEvents(); в ваш тесный цикл.

Обратите внимание, что вы перепутали форму сервера и форму клиента;это одна из причин, по которой полезен реальный SSCCE (список кода, известного для компиляции).

Я бы сказал, добро пожаловать в удивительный мир программирования окон под названием pipe .Это не просто, и это не легко.У MSDN есть хороший пример: Как: использовать именованные каналы для связи между процессами по сети , но как бы он ни был обширен, он все еще довольно элементарен.В действительности вам нужно будет либо использовать асинхронный (неблокирующий) ввод-вывод, либо использовать пул потоков (System.Threading.ThreadPool), если вы хотите, чтобы ваш сервер мог обрабатывать произвольное количество одновременно подключенных клиентов.

...