質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

TCP

TCP(Transmission Control Protocol)とは、トランスポート層のプロトコルで、コネクション型のデータサービスです。

Q&A

解決済

1回答

829閲覧

Listenし続けるゾンビTCPサーバーソケットが出来上がる

naitou

総合スコア141

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

TCP

TCP(Transmission Control Protocol)とは、トランスポート層のプロトコルで、コネクション型のデータサービスです。

0グッド

0クリップ

投稿2023/08/29 11:30

TcpListenerをStartした後にUseShellExecute=falseで子Processを開始し、TcpListenerをStopすると子Processを終了するまでTCPポートが永遠にListenのままになります。なおTcpListenerをStartする前に、子Processを開始すれば大丈夫です。

以下のコードではメモ帳を閉じるまでTCPポート10000がListen状態になり、クライアント側からアプリケーションデータの送信は正常に行えてしまいます。
なぜこうなってしまうのか、ご意見よろしくお願いします。

C#

1 static class Program{ 2 3 [STAThread] 4 static void Main() 5 { 6 TcpListener tcpListener = new TcpListener(new IPEndPoint(IPAddress.Any ,10000)); 7 tcpListener.Start(); 8 9 var proc = new ProcessStartInfo(); 10 proc.FileName = "notepad.exe"; 11 proc.UseShellExecute = false; 12 var process = Process.Start(proc); 13 14 tcpListener.Stop(); 15 16 process.WaitForExit(); 17 } 18 }

実行環境 .NET Framework4.8

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KOZ6.0

2023/08/29 12:40

ひょっとして Kaspersky を使ってらっしゃいますか? パスワードマネージャーが 127.0.0.1:10000 を Listen しています。 そうでない場合は、管理者権限でコマンドプロンプトを立ち上げ netstat -n -a -b を実行して、何かがポートを Listen していないか確認してみてください。
KOZ6.0

2023/08/30 01:52

見当外れのコメントでしたね。申し訳ありません。
guest

回答1

0

ベストアンサー

確かに.NET Framework4.8ではこの現象が発生しますね。(.NET 7では発生しない)

.NET Frameworkでは、子プロセス起動時に呼ばれるWin32関数 CreateProcess()の引数がbInheritHandles=trueになっているようです。

https://referencesource.microsoft.com/#System/services/monitoring/system/diagnosticts/Process.cs,2120

そうすると子プロセスが親プロセスのハンドルを継承するのでこのような現象が発生するのだと思います。

回避するには

・子プロセスの起動後にTcpListenerを起動(ご記載の通り。ハンドルを継承させない)
・ProcessStartInfoのプロパティUseShellExecute = trueに設定

とすると発生しないようです。

追記:.NET 2.0の頃もこの挙動(仕様)のようです。
https://bytes.com/topic/c-sharp/answers/275592-tcplistener-inherited-child-processes-when-useshellexecute-false

投稿2023/08/29 14:46

編集2023/08/30 05:39
hqf00342

総合スコア273

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KOZ6.0

2023/08/30 01:51

標準入出力をリダイレクトするために、bInheritHandles=true が必要みたいです。 .NET 系ではどうやってるのかなと思ってソースを見たのですが、なにやら DLL を呼び出している様子。 https://source.dot.net/#System.Diagnostics.Process/src/libraries/Common/src/Interop/Unix/System.Native/Interop.ForkAndExecProcess.cs,43 簡単な解決方法は、Microsoft.VisualBasic を参照設定して Interaction.Shell を使うことですかね。 「Interaction.Shell(String, AppWinStyle, Boolean, Int32) メソッド」 https://learn.microsoft.com/ja-jp/dotnet/api/microsoft.visualbasic.interaction.shell
hqf00342

2023/08/30 05:41

@KOZ6.0 さん 補足ありがとうございます。VBのInteraction.Shell()は知りませんでした。
naitou

2023/08/30 09:29

回答ありがとうございます。ハンドルの継承により、このような動作になるということで理解しました。 一応UseShellExecute=trueでも現象は回避できますが、Dos窓が表示されてしまう問題がありました。Interaction.Shellについても確認してみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問