私はそれを理解できるかもしれないと考えて、今日これに戻ってきました。そして、私はやった!答えはとても簡単で、1 年間取得できなかったのはばかげているように感じます。
私が投稿したコードに関する2つのこと:
エラーが発生しやすい、私が書いた愚かで不自然なループの代わりにIPAddress.MaptoIPv6
(MSDN リンクを参照)を使用する必要がありました。
を。後で .NET 4.0 で作業しているときに、サンプルで使用した便利な関数が .NET 4.5 まで利用できないことに気付きました。他の誰かが以前のバージョンの .NET で立ち往生している場合に備えて、私がまとめた簡単なコード サンプルをこの投稿の最後に示します。
実際の解決策: 呼び出すclient.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, 0);
前に呼び出す必要がありますclient.Connect()
。
これは、今日テストするために書いたサンプル アプリケーションの完全なコード例です。::1 と 127.0.0.1 の両方をアドレスとして使用して接続できました。Socket
サーバーは IPv6 用に作成され、クライアントとサーバーの両方でSocketOptionName.IPv6Only
オプションが 0 に設定されていることに注意してください。
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace sixsharp
{
class Program
{
static void Main(string[] args)
{
if(args.Length <= 0) //run as server
RunServer();
else
RunClient(args);
Console.WriteLine("Press enter to close.");
Console.ReadLine();
}
static void RunServer()
{
using(Socket serv = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp))
{
serv.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, 0);
serv.Bind(new IPEndPoint(IPAddress.IPv6Any, 1337));
serv.Listen(5);
Console.Write("Listening for client connection...");
using(Socket client = serv.Accept())
{
Console.WriteLine("Client connection accepted from {0}", client.RemoteEndPoint.ToString());
byte[] buf = new byte[128];
client.Receive(buf, 128, SocketFlags.None);
Console.WriteLine("Got \'{0}\' from client", Encoding.ASCII.GetString(buf));
Console.WriteLine("Echoing response");
client.Send(buf);
client.Shutdown(SocketShutdown.Both);
}
}
Console.WriteLine("Done.");
}
static void RunClient(string[] args)
{
using(Socket client = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp))
{
client.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, 0);
Console.WriteLine("Setting up address, input is {0}", args[0]);
IPEndPoint ep;
try
{
ep = new IPEndPoint(IPAddress.Parse(args[0]), 1337);
}
catch(FormatException fe)
{
Console.WriteLine("IP address was improperly formatted and not parsed.");
Console.WriteLine("Detail: {0}", fe.Message);
return;
}
if(ep.AddressFamily == AddressFamily.InterNetwork)
{
ep = new IPEndPoint(ep.Address.MapToIPv6(), ep.Port);
if(!ep.Address.IsIPv4MappedToIPv6 || ep.Address.AddressFamily != AddressFamily.InterNetworkV6)
{
Console.WriteLine("Error mapping IPv4 address to IPv6");
return;
}
}
Console.WriteLine("Connecting to server {0} ...", ep.ToString());
try
{
client.Connect(ep);
}
catch(Exception ex)
{
Console.WriteLine("Unable to connect.\n Detail: {0}", ex.Message);
return;
}
client.Send(Encoding.ASCII.GetBytes("This is a test message. Hello!"));
byte[] buf = new byte[128];
client.Receive(buf);
Console.WriteLine("Got back from server: {0}", Encoding.ASCII.GetString(buf));
client.Shutdown(SocketShutdown.Both);
}
Console.WriteLine("Done.");
}
}
}
クライアント出力:
アドレスを設定しています。入力は 10.2.6.179
です サーバーに接続しています [::ffff:10.2.6.179]:1337 ... サーバー
から戻りました: これはテスト メッセージです。こんにちは!
終わり。
Enter キーを押して閉じます。
サーバー出力:
クライアント接続をリッスンしています... [::ffff:10.2.6.179] から受け入れられたクライアント接続:56275
'これはテスト メッセージです。こんにちは!
' クライアントからの
エコー応答
が完了しました。
Enter キーを押して閉じます。
以前のバージョンの .NET にない便利な関数を提供する拡張メソッドの例:
static class IPAddressExtensions
{
public static IPAddress MapToIPv6(this IPAddress addr)
{
if(addr.AddressFamily != AddressFamily.InterNetwork)
throw new ArgumentException("Must pass an IPv4 address to MapToIPv6");
string ipv4str = addr.ToString();
return IPAddress.Parse("::ffff:" + ipv4str);
}
public static bool IsIPv4MappedToIPv6(this IPAddress addr)
{
bool pass1 = addr.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6, pass2;
try
{
pass2 = (addr.ToString().StartsWith("0000:0000:0000:0000:0000:ffff:") ||
addr.ToString().StartsWith("0:0:0:0:0:ffff:") ||
addr.ToString().StartsWith("::ffff:")) &&
IPAddress.Parse(addr.ToString().Substring(addr.ToString().LastIndexOf(":") + 1)).AddressFamily == AddressFamily.InterNetwork;
}
catch
{
return false;
}
return pass1 && pass2;
}
}