44

それぞれが NamedPipeServer (名前付きパイプ IPC 用に .net 3.5 で追加されたマネージド型) を作成し、クライアントの接続 (ブロック) を待機する多数のスレッドを生成するアプリケーションを開始します。コードは意図したとおりに機能します。

private void StartNamedPipeServer()
  {
    using (NamedPipeServerStream pipeStream =
                    new NamedPipeServerStream(m_sPipeName, PipeDirection.InOut, m_iMaxInstancesToCreate, PipeTransmissionMode.Message, PipeOptions.None))
    {
      m_pipeServers.Add(pipeStream);
      while (!m_bShutdownRequested)
      {
        pipeStream.WaitForConnection();
        Console.WriteLine("Client connection received by {0}", Thread.CurrentThread.Name);
        ....  

ここで、このプロセスを完全に停止するための Shutdown メソッドも必要です。通常の bool フラグ isShutdownRequested トリックを試しました。ただし、パイプストリームは WaitForConnection() 呼び出しでブロックされたままになり、スレッドは終了しません。

public void Stop()
{
   m_bShutdownRequested = true;
   for (int i = 0; i < m_iMaxInstancesToCreate; i++)
   {
     Thread t = m_serverThreads[i];
     NamedPipeServerStream pipeStream = m_pipeServers[i];
     if (pipeStream != null)
     {
       if (pipeStream.IsConnected)
          pipeStream.Disconnect();
       pipeStream.Close();
       pipeStream.Dispose();
     }

     Console.Write("Shutting down {0} ...", t.Name);
     t.Join();
     Console.WriteLine(" done!");
   }
} 

Join は決して戻りません。

私が試したことはありませんが、機能する可能性があるオプションは、Thread.Abort を呼び出して例外を処理することです。しかし、それは正しくありません..何か提案があれば

更新 2009-12-22
以前に投稿できなくて申し訳ありません.. これは、キム ハミルトン (BCL チーム) からの返信として受け取ったものです。

割り込み可能な WaitForConnection を行う「正しい」方法は、BeginWaitForConnection を呼び出し、コールバックで新しい接続を処理し、パイプ ストリームを閉じて接続の待機を停止することです。パイプが閉じている場合、EndWaitForConnection は ObjectDisposedException をスローし、コールバック スレッドがこれをキャッチして未解決の端をクリーンアップし、クリーンに終了します。

これはよくある質問であることを認識しているため、私のチームの誰かが近日中にブログを書く予定です。

4

7 に答える 7

48

これは安っぽいですが、これが私がうまくいった唯一の方法です。「偽の」クライアントを作成し、名前付きパイプに接続して、WaitForConnection を通過します。毎回動作します。

また、 Thread.Abort() でもこの問題は解決しませんでした。


_pipeserver.Dispose();
_pipeserver = null;

using (NamedPipeClientStream npcs = new NamedPipeClientStream("pipename")) 
{
    npcs.Connect(100);
}
于 2009-07-28T02:36:32.783 に答える
8

次の拡張方法を使用できます。'ManualResetEvent cancelEvent'が含まれていることに注意してください。このイベントを別のスレッドから設定して、待機中の接続メソッドが今すぐ中止してパイプを閉じる必要があることを通知できます。m_bShutdownRequestedを設定するときにcancelEvent.Set()を含めると、シャットダウンは比較的適切に行われる必要があります。

    public static void WaitForConnectionEx(this NamedPipeServerStream stream, ManualResetEvent cancelEvent)
    {
        Exception e = null;
        AutoResetEvent connectEvent = new AutoResetEvent(false);
        stream.BeginWaitForConnection(ar =>
        {
            try
            {
                stream.EndWaitForConnection(ar);
            }
            catch (Exception er)
            {
                e = er;
            }
            connectEvent.Set();
        }, null);
        if (WaitHandle.WaitAny(new WaitHandle[] { connectEvent, cancelEvent }) == 1)
            stream.Close();
        if (e != null)
            throw e; // rethrow exception
    }
于 2012-05-07T15:57:18.763 に答える
0

機能する 1 つの方法は、WaitForConnection の直後に m_bShutdownRequested をチェックすることです。

シャットダウン プロセス中に bool を設定します。その後、既存のすべてのパイプにダミー メッセージを送信して、接続を開き、ブール値をチェックして、正常にシャットダウンするようにします。

于 2009-07-14T01:23:48.583 に答える
-1
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Pipes;
using System.Threading;
using System.Windows;
using System.Windows.Controls;

namespace PIPESERVER
{
    public partial class PWIN : UserControl
   {
    public string msg = "", cmd = "", text = "";
    public NamedPipeServerStream pipe;
    public NamedPipeClientStream dummyclient;
    public string PipeName = "PIPE1";
    public static string status = "";
    private static int numThreads = 2;
    int threadId;
    int i;
    string[] word;
    char[] buffer;
    public StreamString ss;

    public bool ConnectDummyClient()
    {
        new Thread(() =>
        {
            dummyclient = new NamedPipeClientStream(".", "PIPE1");
            try
            {
                dummyclient.Connect(5000); // 5 second timeout
            }
            catch (Exception e)
            {
                Act.m.md.AMsg(e.Message); // Display error msg
                Act.m.console.PipeButton.IsChecked = false;
            }
        }).Start();
        return true;
    }

    public bool RaisePipe()
    {
        TextBlock tb = Act.m.tb;
        try
        {
            pipe = new NamedPipeServerStream("PIPE1", PipeDirection.InOut, numThreads);
            threadId = Thread.CurrentThread.ManagedThreadId;
            pipe.WaitForConnection();
            Act.m.md.Msg("Pipe Raised");
            return true;
        }
        catch (Exception e)
        {
            string err = e.Message;
            tb.Inlines.Add(new Run("Pipe Failed to Init on Server Side"));
            tb.Inlines.Add(new LineBreak());
            return false;
        }
    }

    public void ServerWaitForMessages()
    {
        new Thread(() =>
        {
            cmd = "";
            ss = new StreamString(pipe);
            while (cmd != "CLOSE")
            {
                try
                {
                    buffer = new char[256];
                    text = "";
                    msg = ss.ReadString().ToUpper();
                    word = msg.Split(' ');
                    cmd = word[0].ToUpper();
                    for (i = 1; i < word.Length; i++) text += word[i] + " ";
                    switch (cmd)
                    {
                        case "AUTHENTICATE": ss.WriteString("I am PIPE1 server"); break;
                        case "SOMEPIPEREQUEST":ss.WriteString(doSomePipeRequestReturningString()):break;
                        case "CLOSE": ss.WriteString("CLOSE");// reply to client
                            Thread.Sleep(1000);// wait for client to pick-up shutdown message
                            pipe.Close();
                            Act.m.md.Msg("Server Shutdown ok"); // Server side message
                            break;
                    }
                }
                catch (IOException iox)
                {
                    string error = iox.Message;
                    Act.m.md.Msg(error);
                    break;
                }
            }
        }).Start();
    }

    public void DummyClientCloseServerRequest()
    {
        StreamString ss = new StreamString(dummyclient);
        ss.WriteString("CLOSE");
        ss.ReadString();
    }

//使用方法、StackPanel 内に ToggleButton を配置し、次のようにコードに戻します。

private void PipeButton_Checked(object sender, RoutedEventArgs e)
    {
        Act.m.pwin.ConnectDummyClient();
        Act.m.pwin.RaisePipe();
    }
private void PipeButton_Unchecked(object sender, RoutedEventArgs e)
    {
        Act.m.pwin.DummyClientCloseServerRequest();
        Act.m.console.WaitButton.IsChecked = false;
        Keyboard.Focus(Act.m.md.tb1);
    }
private void WaitButton_Checked(object sender, RoutedEventArgs e)
    {
        Act.m.pwin.Wait();
    }
private void WaitButton_Unchecked(object sender, RoutedEventArgs e)
    {
    }

//私にとって魅力のように働きました。敬具 zzzbc }

于 2016-09-07T11:11:05.030 に答える