Закрывается канал named pipes

373
31 марта 2017, 21:53

Доброго дня. Задача вкратце в следующем: существует некий сервер (NamedPipeServerStream), который принимает входящие подключения клиентов (NamedPipeClientStream), поддерживает их и при необходимости рассылает им сообщения. Клиент и сервер реализованы в виде небольших классов, кроме того существует вспомогательный класс, описывающий объект Connection, создаваемый для каждого подключенного клиента. Проблема заключается в том, что сервер принимает подключение, но сразу после этого свойство IsConnected переходит в false. Никак не могу понять в какой момент и почему это происходит, но судя по отладочной информации объект уничтожается. Буду благодарен за советы.

PipeClient

public class PipeClient : IDisposable
{
    private readonly string _pipeName;
    private NamedPipeClientStream _pipeStream;
    private StreamReader _streamReader;
    private byte[] _buffer;
    private object _pipeState = new object();
    public event MessageRecievedHandler OnMessageRecieved;
    /// <summary>
    /// Gets the underlying <c>PipeStream</c> object.
    /// </summary>
    public NamedPipeClientStream PipeStream { get { return _pipeStream; } }
    /// <summary>
    /// Gets a value indicating whether the <see cref="PipeStream"/> object is connected or not.
    /// </summary>
    public bool IsConnected { get { return _pipeStream.IsConnected; } }
    /// <summary>
    /// Main constructor.
    /// </summary>
    /// <param name="pipeName">The name of the channel being created.</param>
    public PipeClient(string pipeName)
    {
        if (String.IsNullOrEmpty(pipeName))
        {
            throw new IOException("Null or empty pipe name");
        }
        else
        {
            this._pipeName = pipeName;
        }
    }
    public bool ConnectAndWaitForMessage()
    {
        if (_pipeStream != null) return false;
        try
        {
            _pipeStream = new NamedPipeClientStream(".", this._pipeName, PipeDirection.In, PipeOptions.Asynchronous);
            _pipeStream.Connect();
            _buffer = new Byte[255];
            _pipeStream.BeginRead(_buffer, 0, _buffer.Length, PipeReadCallback, _pipeState);
            return true;
        }
        catch
        {
            //TODO
            return false;
        }
    }
    private void PipeReadCallback(IAsyncResult ar)
    {
        int bytesRead = 0;
        // if port serial is open and..
        if (_pipeStream.IsConnected)
        {
            // the stream can read then..
            if (_pipeStream.CanRead)
            {
                // wait for asynchronous read to be completed
                bytesRead = _pipeStream.EndRead(ar);
                //_pipeStream.Flush();
            }
        }
        if (bytesRead > 0)
        {
            if (OnMessageRecieved != null)
                OnMessageRecieved(this, new MessageRecievedEventArgs(_buffer));
        }
    }

    public void Dispose()
    {
        throw new NotImplementedException();
    }
}

PipeServer:

    public delegate void ClientConnectedEventHandler(object sender, PipeConnection connection);
/// <summary>
/// The class provides server-side tools for client-server interaction by named pipes.
/// </summary>
public class PipeServer
{
    private readonly string _pipeName;
    private NamedPipeServerStream _pipeStream;
    private bool isListeningToClients = false;
    private List<PipeConnection> connectionsList;
    public event ClientConnectedEventHandler OnClientConnected;
    /// <summary>
    /// Returns the number of clients connected.
    /// </summary>
    public int ClientsCount
    {
        get
        {
            return connectionsList.Count;
        }
    }
    /// <summary>
    /// Creates a new instance of the class PipeServer.
    /// </summary>
    /// <param name="pipeName">Name of the created named pipe.</param>
    public PipeServer(string pipeName)
    {
        if (String.IsNullOrEmpty(pipeName))
        {
            throw new IOException("Null or empty pipe name");
        }
        else
        {
            this._pipeName = pipeName;
            this.isListeningToClients = true;
            this.connectionsList = new List<PipeConnection>();
            ListenForPipeClients();
        }
    }
    /// <summary>
    /// Sends a message to all connected clients. Updates the list of connected.
    /// </summary>
    /// <param name="message">Text message to send.</param>
    public void SendMessage(string message)
    {
        if (!this.isListeningToClients || connectionsList.Count == 0)
            return;
        List<PipeConnection> connListTmp = new List<PipeConnection>();
        byte[] _buffer = Encoding.UTF8.GetBytes(message);
        foreach (PipeConnection conn in connectionsList)
        {
            if (conn.IsConnected && conn.CanWrite)
            {
                try
                {
                    connListTmp.Add(conn);
                    conn.BaseStream.BeginWrite(_buffer, 0, _buffer.Length, new AsyncCallback(OnMessageAsyncSend), conn.BaseStream);
                }
                catch (Exception e)
                {
                    Console.WriteLine("Error occures: {0}.", e.Message);
                }
            }
            else conn.Close();
        }
        connectionsList = connListTmp;
    }

    /// <summary>
    /// Create new NamedPipeServerStream for listening to pipe client connection
    /// </summary>
    private void ListenForPipeClients()
    {
        if (!this.isListeningToClients)
            return;
        try
        {
            if (_pipeStream == null)
                _pipeStream = new NamedPipeServerStream(_pipeName, PipeDirection.Out, 5, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
            IAsyncResult result = _pipeStream.BeginWaitForConnection(OnPipeConnected, _pipeStream);
            Console.WriteLine("Waiting for client connection...");
        }
        catch (ObjectDisposedException)
        {
            //// Catch ObjectDisposedException if server was stopped. Then do nothing.
        }
        catch (Exception e)
        {
            Console.WriteLine("Error occures: {0}. Restart pipe server...", e.Message);
            //ListenForPipeClients();
        }
    }
    /// <summary>
    /// Async callback on client connected action
    /// </summary>
    /// <param name="asyncResult">Async result</param>
    private void OnPipeConnected(IAsyncResult asyncResult)
    {
        using (var conn = (NamedPipeServerStream)asyncResult.AsyncState)
        {
            try
            {
                conn.EndWaitForConnection(asyncResult);
                Console.WriteLine("Client connected.");
                PipeConnection clientConnection = new PipeConnection(conn);
                connectionsList.Add(clientConnection);
                if (OnClientConnected != null)
                    OnClientConnected(this, clientConnection);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }
        ListenForPipeClients();
    }
    private void OnMessageAsyncSend(IAsyncResult ar)
    {
        using (var conn = (NamedPipeServerStream)ar.AsyncState)
        {
            try
            {
                conn.EndRead(ar);
                conn.Flush();
                Console.WriteLine("Message sent successfully!");
            }
            catch (Exception e)
            {
                Console.WriteLine("Error occures: {0}.", e.Message);
            }
        }
    }
    public void StopListening()
    {
        if (!this.isListeningToClients)
            return;
        this.isListeningToClients = false;
        Console.WriteLine("Close all active connections...");
        if (connectionsList.Count > 0)
        {
            foreach (PipeConnection conn in connectionsList)
            {
                if (conn.IsConnected)
                    conn.Close();
            }
        }
    }
}

Connection:

    public class PipeConnection
{
    /// <summary>
    /// Gets the connection's unique identifier.
    /// </summary>
    public readonly int Id;
    /// <summary>
    /// Gets the connection's name.
    /// </summary>
    //public string Name { get; }
    /// <summary>
    /// Gets the underlying <c>PipeStream</c> object.
    /// </summary>
    public PipeStream BaseStream { get; private set; }
    /// <summary>
    ///     Gets a value indicating whether the <see cref="BaseStream"/> object is connected or not.
    /// </summary>
    /// <returns>
    ///     <c>true</c> if the <see cref="BaseStream"/> object is connected; otherwise, <c>false</c>.
    /// </returns>
    public bool IsConnected
    {
        get { return BaseStream.IsConnected; }
    }
    /// <summary>
    ///     Gets a value indicating whether the current stream supports read operations.
    /// </summary>
    /// <returns>
    ///     <c>true</c> if the stream supports read operations; otherwise, <c>false</c>.
    /// </returns>
    public bool CanRead
    {
        get { return BaseStream.CanRead; }
    }
    /// <summary>
    ///     Gets a value indicating whether the current stream supports write operations.
    /// </summary>
    /// <returns>
    ///     <c>true</c> if the stream supports write operations; otherwise, <c>false</c>.
    /// </returns>
    public bool CanWrite
    {
        get { return BaseStream.CanWrite; }
    }
    /// <summary>
    /// Constructs a new <c>PipeConnection</c> object that reads from and writes to the given <paramref name="stream"/>.
    /// </summary>
    /// <param name="stream">Stream to read from and write to</param>
    public PipeConnection(PipeStream stream)
    {
        BaseStream = stream;
    }
    /// <summary>
    ///     Closes the current stream and releases any resources (such as sockets and file handles) associated with the current stream.
    /// </summary>
    public void Close()
    {
        BaseStream.Close();
        BaseStream.Dispose();
    }
}
READ ALSO
Получения числа из имена контрола

Получения числа из имена контрола

привет есть кодЯ в цикле перебираю дочерние картинки грида

282
Почему не обновляется DataGridView?

Почему не обновляется DataGridView?

"Это главная форма она должна обновить дата грид но она обновляется лишь после 2 клика на кнопкуПри этом добавляется новая строка в БД но она...

359
Get-запрос. Ошибка "Сервер нарушил протокол. Section=ResponseStatusLine

Get-запрос. Ошибка "Сервер нарушил протокол. Section=ResponseStatusLine

Доброе время суток! При вызове Get метода, catch(Exception ex) выводит ошибку "Сервер нарушил протоколSection=ResponseStatusLine

378