-1

さまざまな Web 要求にバインドする必要がある 5 つの異なる IP があります。

以下のサンプルコードをご覧ください。Call1() は完全に機能します。しかし、Call2() で List< Task > を使用しようとすると、間違った IP が要求にバインドされます (要求されたサイトの IIS ログで IP を再確認します)。

助けてください!!!

    class Program
    {

        private static string[] IPs = new string[] { "xxx.xxx.xx.xxx", "xxx.xxx.xx.xxx", "xxx.xxx.xx.xxx", "xxx.xxx.xx.xxx", "xxx.xxx.xx.xxx" };
        private static string Url = "http://myfakedomain.com/{0}.aspx";

        static void Main(string[] args)
        {
            Call1();
            Call2();
        }

        static void Call1()
        {
            WebHandler web = new WebHandler();

                foreach (var ip in IPs)
                {
                    web.MakeWebRequest(String.Format(Url,ip), ip);
                }
        }

        static void Call2()
        {
            WebHandler web = new WebHandler();
            List<Task> tasks = new List<Task>();

                foreach (var ip in IPs)
                {
                   var ipCopy = ip;
                    tasks.Add(Task<bool>.Factory.StartNew(() => web.MakeWebRequest(String.Format(Url, ipCopy ), ipCopy )));
                }

                Task.WaitAll(tasks.ToArray());
        }

    }

    public class WebHandler
    {
        public bool MakeWebRequest(string Url, string IP)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url);
            request.ServicePoint.BindIPEndPointDelegate = (servicePoint, remoteEndPoint, retryCount) => new IPEndPoint(IPAddress.Parse(IP), 0);

            request.KeepAlive = false;

            using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
            {
                using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.ASCII))
                {
                    string html = reader.ReadToEnd();
                }
            }

            return true;
        }
    }

以下は Call2() の IIS ログです。

2012-10-23 01:53:20 xxx.xxx.xx.xxx GET /xxx.xxx.xx.244.aspx - 80 - xxx.xxx.xx.242 - 200 0 0 1185
2012-10-23 01:53:20 xxx.xxx.xx.xxx GET /xxx.xxx.xx.241.aspx - 80 - xxx.xxx.xx.242 - 200 0 0 1201
2012-10-23 01:53:21 xxx.xxx.xx.xxx GET /xxx.xxx.xx.243.aspx - 80 - xxx.xxx.xx.242 - 200 0 0 608
2012-10-23 01:53:21 xxx.xxx.xx.xxx GET /xxx.xxx.xx.242.aspx - 80 - xxx.xxx.xx.242 - 200 0 0 624
2012-10-23 01:53:21 xxx.xxx.xx.xxx GET /xxx.xxx.xx.245.aspx - 80 - xxx.xxx.xx.242 - 200 0 0 218
4

1 に答える 1

0

これは、ラムダ式を扱っているときに foreach ループの変数クロージャとよく混同されます。基本的に、Call2() コードを以下に変更すると、期待どおりに動作するはずです。正確な理由に興味がある場合は、Eric Lippert のブログ投稿で優れた説明を確認してください。

static void Call2()
{
    WebHandler web = new WebHandler();
    List<Task> tasks = new List<Task>();

    foreach (var ip in IPs)
    {
        var ipCopy = ip;
        tasks.Add(Task<bool>.Factory.StartNew(() => web.MakeWebRequest(String.Format(Url, ipCopy), ipCopy)));
    }

    Task.WaitAll(tasks.ToArray());
}
于 2012-10-24T03:50:15.583 に答える