Executing web requests inside of a loop only works

2020-04-16 19:41发布

问题:

I am taking a string message and breaking it up into chunks so that I can send it to an sms service (that consequently doesn't break it up for you). I after I do my work for break those messages up, I try loop through the resulting array and execute a web request. The problem is that it only works for the first message, and then hangs after that. After a short time, I get an error message saying "The connection was closed unexpectedly." This occurs at the second time it attempts GetResponse(); I've seen a few other posts on here that were simply saying to close and dispose the response and request streams. This isn't working for me at all. This is where my code is currently:

private static void Main(string[] args)
{
    var oldMessage = GetFileString();
    Console.WriteLine(string.Format("Old message: {0}", oldMessage.Length));

    var newMessage = UrlPathEncodeString(oldMessage);
    Console.WriteLine(string.Format("New message: {0}", newMessage.Length));

    var brokenUp = SplitByLength(newMessage, 145).ToArray();
    for(var i = 0; i < brokenUp.Count(); i++)
    {
        brokenUp[i] = brokenUp[i].Insert(0, UrlPathEncodeString(string.Format("({0:D2} of {1:D2})", i + 1, brokenUp.Count())));
        Console.WriteLine(string.Format("Appended length: {0}", brokenUp[i].Length));
    }

    System.Net.ServicePointManager.DefaultConnectionLimit = 100;
    foreach (var block in brokenUp)
    {
        Thread.Sleep(1500);
        SendSms((HttpWebRequest)WebRequest.Create("http://172.20.5.214:90/method/sendsms"), block);
    }
    Console.ReadKey();
}

public static void SendSms(HttpWebRequest request, string message)
{
    //build the request
    var url = "http://ipaddress/method/sendsms";
    //var request = (HttpWebRequest)WebRequest.Create(url);
    request.Method = "POST";
    request.ContentType = "application/x-www-form-urlencoded";

    var fields = "CellNumber={0}&Message={1}";
    fields = string.Format(fields, "16021234567", message);

    var fieldsBytes = Encoding.UTF8.GetBytes(fields);
    request.ContentLength = fieldsBytes.Length;
    var length = fieldsBytes.Length;

    using (var requestStream = request.GetRequestStream())
    {
        requestStream.Write(fieldsBytes, 0, length);

        using (var response = request.GetResponse())
        {
            using (var responseStream = response.GetResponseStream())
            {
                responseStream.Close();
            }
        }
        requestStream.Close();
    }
}

public static byte[] ReadFully(Stream stream)
{
    var buffer = new byte[32768];
    using (var ms = new MemoryStream())
    {
        while (true)
        {
            int read = stream.Read(buffer, 0, buffer.Length);
            if (read <= 0)
                return ms.ToArray();
            ms.Write(buffer, 0, read);
        }
    }
}

回答1:

I've run into cases where response.Close appears to hang if you fail to download the entire contents of the response. Why this is, I don't know, but placing a call to request.Abort before calling Close() solves the problem. I wouldn't expect you to be seeing this problem, though, unless the response could potentially be many megabytes in size.

Also, failing to close the request stream before calling GetResponse might prevent all of the data from being sent. I would suggest calling requestStream.Close before making the request. But again, it seems odd that your code would work the first time but not on subsequent requests.

Your modified code, taking into account the changes I suggested, would be:

using (var requestStream = request.GetRequestStream())
{
    requestStream.Write(fieldsBytes, 0, length);
}

using (var response = request.GetResponse())
{
    using (var responseStream = response.GetResponseStream())
    {
        // read the response here.
        request.Abort();
        responseStream.Close();
    }
}