21

C#アプリケーションが実行されているコンピューターの外部IPを確認する必要があります。

アプリケーションでは、サーバーへの接続(.NETリモーティングを介して)があります。サーバー側でクライアントのアドレスを取得する良い方法はありますか?

(もう少し明確にするために、質問を編集しました。私が少し漠然としていたときに、質問に答えるために最善を尽くしたすべての親切な人々に謝罪します)

解決策:
自分に合った方法を見つけました。CommonTransportKeys.IPAddressにアクセスできるカスタムIServerChannelSinkProviderとIServerChannelSinkを実装することで、CallContextにクライアントIPを簡単に追加できます。

public ServerProcessing ProcessMessage(IServerChannelSinkStack sinkStack, 
    IMessage requestmessage, ITransportHeaders requestHeaders, 
    System.IO.Stream requestStream, out IMessage responseMessage, 
    out ITransportHeaders responseHeaders, out System.IO.Stream responseStream)
{
    try
    {
        // Get the IP address and add it to the call context.
        IPAddress ipAddr = (IPAddress)requestHeaders[CommonTransportKeys.IPAddress];
        CallContext.SetData("ClientIP", ipAddr);
    }
    catch (Exception)
    {
    }

    sinkStack.Push(this, null);
    ServerProcessing srvProc = _NextSink.ProcessMessage(sinkStack, requestmessage, requestHeaders,
        requestStream, out responseMessage, out responseHeaders, out responseStream);

    return srvProc;
}

そして後で(クライアントからリクエストを受け取ったとき)、このようにCallContextからIPを取得します。

public string GetClientIP()
{
    // Get the client IP from the call context.
    object data = CallContext.GetData("ClientIP");

    // If the data is null or not a string, then return an empty string.
    if (data == null || !(data is IPAddress))
        return string.Empty;

    // Return the data as a string.
    return ((IPAddress)data).ToString();
}

これで、IPをクライアントに送り返すことができます。

4

12 に答える 12

19

これは、より深く調べて元の問題を再考しなければならない問題の 1 つです。この場合は、「なぜ外部 IP アドレスが必要なのですか?」

問題は、コンピュータが外部 IP アドレスを持っていない可能性があることです。たとえば、私のラップトップには、ルーターによって割り当てられた内部 IP アドレス (192.168.xy) があります。ルーター自体には内部 IP アドレスがありますが、その「外部」IP アドレスも内部です。これは、DSL モデムとの通信にのみ使用されます。DSL モデムは、実際には外部のインターネットに接続された IP アドレスを持っています。

したがって、本当の問題は、「2 ホップ離れたデバイスのインターネットに面した IP アドレスを取得するにはどうすればよいか」ということになります。答えは、一般的にはありません。少なくとも、すでに却下した whatismyip.com などのサービスを使用したり、アプリケーションに DSL モデムのパスワードをハードコーディングしたり、DSL モデムにクエリを実行したり、管理ページをスクリーン スクレイピングしたりするなど、非常に大規模なハッキングを行わなければなりません (そして、神はあなたを助けてくれます)。モデムを交換した場合)。

編集: これをリファクタリングされた質問「サーバー .NET コンポーネントからクライアントの IP アドレスを取得するにはどうすればよいですか?」に適用します。whatismyip.com のように、サーバーができる最善のことは、インターネットに接続しているデバイスの IP アドレスを提供することです。これは、アプリケーションを実行しているコンピューターの実際の IP アドレスである可能性は低いです。ラップトップに戻ると、インターネットに接続する IP が 75.75.75.75 で、LAN IP が 192.168.0.112 の場合、サーバーは 75.75.75.75 の IP アドレスしか認識できません。これで、私の DSL モデムまで到達します。サーバーが私のラップトップに別の接続を確立したい場合は、最初に DSL モデムと、サーバーと私のラップトップの間にあるルーターを構成して、サーバーからの着信接続を認識し、適切にルーティングする必要があります。やり方はいくつかありますが、

実際にサーバーからクライアントへの接続を確立しようとしている場合は、WTF の領域を掘り下げているため (または、少なくともアプリケーションのデプロイがはるかに困難になっているため)、設計を再考してください。

于 2008-09-15T20:20:21.343 に答える
6

Dns.GetHostEntry(Dns.GetHostName()); IPアドレスの配列を返します。最初のものは外部IPである必要があり、残りはNATの背後にあるものになります。

それで:

IPHostEntry IPHost = Dns.GetHostEntry(Dns.GetHostName());
string externalIP = IPHost.AddressList[0].ToString();

編集:

一部の人にとってはこれが機能しないという報告があります。私にとっては問題ありませんが、ネットワーク構成によっては機能しない場合があります。

于 2008-09-15T20:06:38.007 に答える
6

私にぴったりの方法を見つけました。CommonTransportKeys.IPAddress にアクセスできるカスタム IServerChannelSinkProvider と IServerChannelSink を実装することで、CallContext にクライアント IP を簡単に追加できます。

public ServerProcessing ProcessMessage(IServerChannelSinkStack sinkStack, 
    IMessage requestmessage, ITransportHeaders requestHeaders, 
    System.IO.Stream requestStream, out IMessage responseMessage, 
    out ITransportHeaders responseHeaders, out System.IO.Stream responseStream)
{
    try
    {
        // Get the IP address and add it to the call context.
        IPAddress ipAddr = (IPAddress)requestHeaders[CommonTransportKeys.IPAddress];
        CallContext.SetData("ClientIP", ipAddr);
    }
    catch (Exception)
    {
    }

    sinkStack.Push(this, null);
    ServerProcessing srvProc = _NextSink.ProcessMessage(sinkStack, requestmessage, requestHeaders,
        requestStream, out responseMessage, out responseHeaders, out responseStream);

    return srvProc;
}

そして後で(クライアントからリクエストを受け取ったとき)、次のように CallContext から IP を取得します。

public string GetClientIP()
{
    // Get the client IP from the call context.
    object data = CallContext.GetData("ClientIP");

    // If the data is null or not a string, then return an empty string.
    if (data == null || !(data is IPAddress))
        return string.Empty;

    // Return the data as a string.
    return ((IPAddress)data).ToString();
}

これで、IP をクライアントに送り返すことができます。

于 2009-08-23T20:53:17.653 に答える
5

http://www.whatismyip.com/automation/n09230945.aspを使用すると、自動ルックアップのためだけにIPのみが出力されます。

他の誰かに依存しないものが必要な場合は、独自のページhttp://www.unkwndesign.com/ip.phpを作成してください。これは簡単なスクリプトです。

<?php
echo 'Your Public IP is: ' . $_SERVER['REMOTE_ADDR'];
?>

ここでの唯一の欠点は、リクエストの作成に使用されたインターフェースの外部IPのみを取得することです。

于 2008-09-15T20:06:33.560 に答える
4

Jonathan Holland の答えは基本的には正しいですが、Dns.GetHostByName の背後にある API 呼び出しはかなり時間がかかり、コードを 1 回だけ呼び出す必要があるように結果をキャッシュすることをお勧めします。

于 2008-09-15T20:13:42.997 に答える
3

主な問題は、パブリック IP アドレスが、アプリケーションを実行しているローカル コンピューターに必ずしも関連付けられていないことです。内部ネットワークからファイアウォールを介して変換されます。ローカル ネットワークに問い合わせずにパブリック IP を取得するには、インターネット ページにリクエストを送信し、結果を返します。公開されている WhatIsMyIP.com タイプのサイトを使用したくない場合は、簡単にサイトを作成して自分でホストすることができます。できれば Web サービスとして、アプリケーション内から簡単な SOAP 準拠の呼び出しを行うことができます。舞台裏の投稿ほどスクリーン キャプチャを行い、応答を読む必要はありません。

于 2008-09-15T20:22:44.850 に答える
2

アダプターにバインドされた IP だけが必要な場合は、WMI と Win32_NetworkAdapterConfiguration クラスを使用できます。

http://msdn.microsoft.com/en-us/library/aa394217(VS.85).aspx

于 2008-09-15T20:10:31.960 に答える
2

パトリックのソリューションは私にとってはうまくいきます!

重要な変更を1 つ行いました。処理中のメッセージで、次のCallContextコードを使用して設定しました:

// try to set the call context
LogicalCallContext lcc = (LogicalCallContext)requestMessage.Properties["__CallContext"];
if (lcc != null)
{
    lcc.SetData("ClientIP", ipAddr);
}

これにより、IP アドレスが正しい CallContext に配置されるため、後で で取得できます GetClientIP()

于 2009-05-29T20:53:47.010 に答える
1

クライアントに が接続されていると仮定すると、System.Net.Sockets.TcpClient(サーバー上で) を使用できますclient.Client.RemoteEndPoint。これSystem.Net.EndPointにより、クライアントを指すようになります。サブクラスのインスタンスを含む必要System.Net.IPEndPointありますが、その条件についてはわかりません。それにキャストした後、そのプロパティをチェックしてAddress、クライアントのアドレスを取得できます。

要するに、私たちは持っています

using (System.Net.Sockets.TcpClient client = whatever) {
    System.Net.EndPoint ep = client.Client.RemoteEndPoint;
    System.Net.IPEndPoint ip = (System.Net.IPEndPoint)ep;
    DoSomethingWith(ip.Address);
}

幸運を。

于 2008-09-15T22:34:57.590 に答える
0

理論的には、外部の「ヘルプ」を使用しないと、ルーターの背後にいる間 (無効な IP 範囲を使用している場合など) にそのようなことを行うことはできないと思います。

于 2008-09-15T20:18:23.907 に答える
-1

基本的に、 http: //whatismyipaddress.comのWebRequestを実行することにより、返されたページを解析できます。

http://www.dreamincode.net/forums/showtopic24692.htm

于 2008-09-15T20:05:32.597 に答える
-3

これを行う最も信頼できる方法は、http://checkip.dyndns.org/などのサイトをチェックすることです。これは、実際にネットワークの外部に移動するまで、外部IPを見つけることができないためです。ただし、そのようなURLをハードコーディングすると、最終的に失敗する可能性があります。現在のIPがRFC1918プライベートアドレス(192.168.x.xこれらの中で最もよく知られている)のように見える場合にのみ、このチェックを実行することをお勧めします。

それができない場合は、ファイアウォールの外部にある独自の同様のサービスを実装できるため、少なくともファイアウォールが壊れているかどうかを知ることができます。

于 2008-09-15T20:07:01.687 に答える