Доброго дня. Задача вкратце в следующем: существует некий сервер (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();
}
}
Сборка персонального компьютера от Artline: умный выбор для современных пользователей