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

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

ただいまの
回答率

90.34%

  • C#

    7674questions

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

  • TCP

    169questions

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

  • WCF

    14questions

    Windows Communication Foundation

Windowsサービスを用いたWCFサービスでクライアントとTCP通信する際の例外を回避したい2

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 2,632

paul

score 14

前提・実現したいこと

WCFサービスを、Windowsサービスにホストさせて、クライアントとTCP通信したいと思い、下記の記事を参考に実装進めております。

How to: Host WCF in a Windows Service Using TCP

例外を発生することなく、正常にTCPでクラサバ通信を行いたいと考えています。

発生している問題・エラーメッセージ

サービスクライアントインスタンスをオープンするときに、例外が発生してしまいます。

なお、リモート先のマシンはファイヤーウォールを有効にしていて、該当のポート50000番(50000という数字は一例です)について例外設定(送受信ともに許可)しています。
そして、ポイントはファイヤーウォールを無効にすると例外が発生せず、正常にやり取りができていることです。

 Service1Client client = null;
 string address = "net.tcp://<RemoteMachineName>:50000/MyService";
 client = new Service1Client ("netTcpMyEndpoint", address);
 client.Open(); // <-- ここで例外 'System.Net.Sockets.SocketException'発生

// MyServiceClientはSystem.ServiceModel.ClientBase<TestProject.MyServiceReference.IService1>を継承し、
// TestProject.DebugWcfServiceReference.IService1を実装しているクラスです。
// これは Visual Studioにてサービス参照追加をした際に、自動で生成されるクラスです。

下記の例外が発生します。

<メッセージ>
'System.Net.Sockets.SocketException'
例外メッセージ : ”ホスト <RemoteMachineName> に対する DNS エントリが存在しません。”

<トレース>
例外がスローされました: 'System.Net.Sockets.SocketException' (System.dll の中)
例外がスローされました: 'System.ServiceModel.EndpointNotFoundException' (System.ServiceModel.dll の中)
例外がスローされました: 'System.Reflection.TargetInvocationException' (mscorlib.dll の中)
例外がスローされました: 'System.ServiceModel.EndpointNotFoundException' (mscorlib.dll の中)

Windowsサービスクラス

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceModel;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
using WcfServiceLibrary1;

namespace WindowsService1
{
    public partial class Service : ServiceBase
    {
        internal static ServiceHost myServiceHost = null;

        public Service()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
            try
            {
                if (myServiceHost != null)
                {
                    myServiceHost.Close();
                }
                myServiceHost = new ServiceHost(typeof(Service1));
                myServiceHost.Open();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.StackTrace);
                throw;
            }
        }

        protected override void OnStop()
        {
            try
            {
                if (myServiceHost != null)
                {
                    myServiceHost.Close();
                    myServiceHost = null;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                throw;
            }
        }
    }
}

ホスト側のApp.Config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <startup> 
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
  </startup>
  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>
  <system.web>
    <compilation debug="true" />
  </system.web>
  <!-- サービス ライブラリ プロジェクトの展開時に、構成ファイルの内容をホストの app.config ファイルに追加する
  必要があります。System.Configuration は、ライブラリの構成ファイルをサポートしていません。 -->
  <system.serviceModel>
    <bindings>
      <netTcpBinding>
        <binding name="netTcpServerBinding" portSharingEnabled="true">
          <security mode="None"/>
        </binding>
      </netTcpBinding>
    </bindings>
    <services>
      <service name="WcfServiceLibrary1.Service1">
        <endpoint address="" binding="netTcpBinding" bindingConfiguration="netTcpServerBinding"
          name="netTcpMyEndpoint" contract="WcfServiceLibrary1.IService1">
          <identity>
            <dns value="localhost" />
          </identity>
        </endpoint>
        <endpoint address="mex" binding="mexTcpBinding" bindingConfiguration=""
          contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="net.tcp://localhost:50000/Service1" />
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- メタデータ情報の開示を避けるには、
          展開する前に下の値を false に設定します -->
          <serviceMetadata httpGetEnabled="False" httpsGetEnabled="False"/>
          <!-- デバッグ目的で障害発生時の例外の詳細を受け取るには、
          下の値を true に設定します。例外情報の開示を避けるには、
          展開する前に false に設定します -->
          <serviceDebug includeExceptionDetailInFaults="False" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

</configuration>

実試したこと

・上記の参考サイトのコードにおけるService1というクラス名が、WCFサービスとWindowsサービスで重複していたので、WindowsサービスのほうをServiceに名前変更しております。
・ファイヤーウォールの例外設定の変更
→ TCP 0-60000 を送受信許可、UDP 53を送受信許可
→ UDP 0-60000 を送受信許可 ← 「サービスクライアントインスタンスをオープンするときに、例外が発生」という問題は解決されました

補足情報(言語/FW/ツール等のバージョンなど)

C# 6.0
Visual Studio 2015

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+2

ファイアウォールでDNSへのアクセス(TCP/UDP53ポート等)をブロックしてたりしませんか?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/02/23 14:43 編集

    早速のご回答ありがとうございます。

    TCPは試験的に全ポート開けてみて試していました。 
    「実施したこと」に書くべきでした。追記させていただきます。
    ですが、UDPまではあけていませんでしたので、UDPの53番を許可してみました。
    しかし結果は変わっていないように見受けられます。。。

    ご回答ありがとうございます。

    キャンセル

  • 2017/02/23 15:25 編集

    YAmaGNZ様

    ご報告します。 結論から言うと通信ができました。
    先ほど、UDPのポート53のみを許可しましたが、0-60000の範囲で許可したところ、通信できるようになりました。

    この結果から以下の2つほど疑問が生まれました。
    ・TCP通信を行っているのに、なぜUDPの許可が必要であるのか。
    ・一体何番のポートが問題の対象だったのか。(YAmaGNZ様がおっしゃるように、例外メッセージを見るに、DNS関係の問題なのかもしれないと指摘されてから感じましたが、DNSのポートは53番だと私も理解しています。しかし53番以外を開けた結果うまくいったように思います。)

    これらのことについてお分かりになる方がいらっしゃったらご教授願いたく思います。

    「Windowsサービスを用いたWCFサービスでクライアントとTCP通信する際の例外を回避したい2」という問題は解決しましたため、本質問は解決です。
    このページも解決としたいところですが、本質問が記載されていたほうがスムーズに回答を得られると判断しますので、本日中は上記疑問が解消するまでは未解決のままにします。

    YAmaGNZ様、ご回答ありがとうございます。

    キャンセル

  • 2017/02/23 16:05

    DNS で使用されるポートについての記事を見つけましたので取り急ぎ貼ります。

    ネットワークの DNS で使用されるポート
    https://technet.microsoft.com/ja-jp/library/dd197515(v=ws.10).aspx

    疑問解消次第、解決にします。

    キャンセル

  • 2017/02/23 16:32

    net.tcp://<RemoteMachineName>:50000/MyService
    これでアクセスしようとすると、<RemoteMachineName>をIPアドレスに変換しようとDNSへの問い合わせが行われます。
    DNSへの問い合わせは通常は速度を速くしようとUDPパケットにて行われます。
    これがファイアウォールでUDPポートを開放しないとだめな理由となります。

    また、ファイアウォールをどのように設定されたか分かりませんが、デフォルトで
    「コアネットワーク - DNS(UDP送信)」の設定があると思うので、そちらのほうとの競合があったのではないかと思います。

    キャンセル

  • 2017/02/23 16:58

    YAmaGNZ様
    再度ご回答ありがとうございます。
    >net.tcp://<RemoteMachineName>:50000/MyService
    >これでアクセスしようとすると、<RemoteMachineName>をIPアドレスに変換しようとDNSへの問い合わせが行われます。
    >DNSへの問い合わせは通常は速度を速くしようとUDPパケットにて行われます。
    >これがファイアウォールでUDPポートを開放しないとだめな理由となります。

    UDPが使用される理由と、DNS問い合わせが発生する理由、とても理解できました。
    ありがとうございます!

    >また、ファイアウォールをどのように設定されたか分かりませんが、デフォルトで
    >「コアネットワーク - DNS(UDP送信)」の設定があると思うので、そちらのほうとの競合があったのではないかと思います。

    こちらですが、競合=同ポートに対して重複した許可設定がある と解釈して話を進めますが、競合があったから通信ができなかったとは考えにくいと判断しています。

    先ほど0-60000の範囲のポートをUDP送受信許可設定したところ通信ができたとご報告しました。

    確かにおっしゃる通り『「コアネットワーク - DNS(UDP送信)」の設定がある』のは事実で、有効になっていました。仮に競合がおこっているのであればUDP送受信で0-60000設定したとしても、53はこの0-60000の範囲にありますので、競合は解消されておりません。

    おそらくこうであろう、という目星が一つ付きました。
    先ほど展開しました、 ネットワークの DNS で使用されるポート(https://technet.microsoft.com/ja-jp/library/dd197515(v=ws.10).aspx)の記事を見ますと、DNSのUDPで使われる53ポートは”応答”の時に使用されるようで、”クエリ”は別の任意のポート番号が使われるようです。それが許可できていないことが問題だったのではないかと考えております。
    そしてその任意のポート番号が0-60000の範囲に入っていたため、0-60000番ポート許可設定によって通信できるようになった。と考えております。
    実際に、プロセスモニターでUDP通信を監視したところ、Open()した瞬間に
    59901
    56429
    51839
    54515
    の4つが使われていることを確認しました。
    TCPやUDPにおけるポート番号の一覧
    https://ja.wikipedia.org/wiki/TCP%E3%82%84UDP%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E3%83%9D%E3%83%BC%E3%83%88%E7%95%AA%E5%8F%B7%E3%81%AE%E4%B8%80%E8%A6%A7

    4 動的・プライベート ポート番号 (49152–65535)
    が使われているのだと判断しています。

    49152–65535など、広範囲にポートをあけてしまうとファイヤーウォールの能力がかなり損なわれてしまうため、コーディング側で”クエリ”のポート番号を静的にできるようにし、指定し、その指定した番号をポートを開けるようにする術をこれから調査しようと思います。

    本問題は解決したと考えます。YAmaGNZ様 どうもありがとうございました。

    キャンセル

同じタグがついた質問を見る

  • C#

    7674questions

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

  • TCP

    169questions

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

  • WCF

    14questions

    Windows Communication Foundation

  • トップ
  • C#に関する質問
  • Windowsサービスを用いたWCFサービスでクライアントとTCP通信する際の例外を回避したい2