用于向web服务发送http post请求的多线程
本文关键字:post 请求 多线程 http web 服务 用于 | 更新日期: 2023-09-27 17:54:58
我想用c#向Web服务发送多个HTTP post请求。例如,如果n=3,则应从3个xml文件发出HTTP post请求,并且响应应写入文件中。一旦前3个请求被发出,接下来的3个请求将被发出。所以我做了下面的代码,但我得到随机输出。但现在我得到要么索引范围异常在内部for循环或内部服务器错误(500)。请提出适当的修改建议。我用的是。net 4.0
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading;
using System.Xml;
using System.Net;
using System.Threading.Tasks;
namespace ConsoleApplication5
{
class Program
{
static void Main(string[] args)
{
int n = 0;
Console.WriteLine("Enter the number");
string s = Console.ReadLine();
int.TryParse(s, out n);
string path = "C:''";
string[] files = null;
files = Directory.GetFiles(path, "*.xml", SearchOption.TopDirectoryOnly);
List<Task> tasks = new List<Task>(files.Length);
for (int i = 0; i < files.Length; i += n)
{
for (int j = 0; j < n; j++)
{
int x = i + j;
if (x < files.Length && files[x] != null)
{
Task t = new Task(() => function(files[x]));
t.Start();
tasks.Add(t);
}
}
if (tasks.Count > 0)
{
Task.WaitAll(tasks.ToArray(), Timeout.Infinite); // or less than infinite
tasks.Clear();
}
}
}
public static void function(string temp)
{
XmlDocument doc = new XmlDocument();
doc.Load(temp);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://10.76.22.135/wpaADws/ADService.asmx");
request.ContentType = "text/xml;charset='"utf-8'"";
request.Accept = "text/xml";
request.Method = "POST";
Stream stream = request.GetRequestStream();
doc.Save(stream);
stream.Close();
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
using (StreamReader rd = new StreamReader(response.GetResponseStream()))
{
string soapResult = rd.ReadToEnd();
doc.LoadXml(soapResult);
File.WriteAllText(temp, doc.DocumentElement.InnerText);
//XmlTextWriter xml=new XmlTextWriter(
Console.WriteLine(soapResult);
Console.ReadKey();
}
}
}
}
此代码有效。说明:
- 首先,用户给出.xml文件的源路径和目标路径。
-
Directory.getFiles()帮助我们获得字符串数组中的.xml文件。(我们必须传递。xml作为参数)
-
所以现在基本上发生的是,对于我们在源部分获得的每个文件,创建一个线程。
- 但是假设用户想一次发送"n"个请求,那么一次创建n个线程。
- 下一组线程不会被创建,除非之前的线程完成执行。 这是由thread.Join()保证的。
在向web服务发出请求后,我们通过getResponse()获得响应,并将响应写入存储在目标路径中的.xml文件中。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using System.Threading; using System.Xml; using System.Net; namespace ConsoleApplication4 { class Program { int flag = 1; string destination; string source; static void Main(string[] args) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("**************************** Send HTTP Post Requests **************************"); int n = 0; Program p = new Program(); Console.WriteLine("Enter the number of requests you want to send at a time"); string s = Console.ReadLine(); int.TryParse(s, out n); Console.WriteLine("Enter Source"); p.source = Console.ReadLine(); Console.WriteLine("Enter Destination"); p.destination = Console.ReadLine(); string[] files = null; files = Directory.GetFiles(p.source, "*.xml", SearchOption.TopDirectoryOnly); Thread[] thread = new Thread[files.Length]; int len = files.Length; for (int i = 0; i<len; i+=n) { int x = i; //Thread.Sleep(5000); for (int j = 0; j < n && x < len; j++) { var localx = x; thread[x] = new Thread(() => function(files[localx], p)); thread[x].Start(); Thread.Sleep(50); //thread[x].Join(); x++; } int y = x - n; for (; y < x; y++) { int t = y; thread[t].Join(); } } // thread[0] = new Thread(() => function(files[0])); //thread[0].Start(); Console.ReadKey(); } public static void function(string temp,Program p) { XmlDocument doc = new XmlDocument(); doc.Load(temp); string final_d=p.destination + "response " + p.flag + ".xml"; p.flag++; HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://10.76.22.135/wpaADws/ADService.asmx"); request.ContentType = "text/xml;charset='"utf-8'""; request.Accept = "text/xml"; request.Method = "POST"; Stream stream = request.GetRequestStream(); doc.Save(stream); stream.Close(); HttpWebResponse response = (HttpWebResponse)request.GetResponse(); using (StreamReader rd = new StreamReader(response.GetResponseStream())) { string soapResult = rd.ReadToEnd(); doc.LoadXml(soapResult); File.WriteAllText(final_d, doc.DocumentElement.InnerText); //XmlTextWriter xml=new XmlTextWriter( Console.WriteLine(soapResult); //Console.ReadKey(); } }
}}
您在原始帖子中遇到的IndexOutOfRangeException
是由于您处理的最后一批文件的索引处理不当造成的。最后一批可以是不完整的,你把它当作固定大小的常规批次
(n=3 in your post)
既然你正在转向TPL和Tasks
,我建议使用Microsoft . net并行编程,以及管道模式,这似乎非常适合你的场景。您可以利用并发集合和生产者/消费者模式以及管道的强大功能,如下所示。BlockingCollection确保了项目和BlockingCollection的并发添加。GetConsumingEnumerable调用为你的集合生成一个消费阻塞枚举器。
const int BUFFER_SIZE = 3; // no concurrent items to process
const string XML_FOLDER_PATH = "<whatever>";
public static void Pipeline()
{
var bufferXmlFileNames = new BlockingCollection<string>(BUFFER_SIZE);
var bufferInputXmlDocuments = new BlockingCollection<XmlDocument>(BUFFER_SIZE);
var bufferWebRequests = new BlockingCollection<HttpWebRequest>(BUFFER_SIZE);
var bufferSoapResults = new BlockingCollection<string>(BUFFER_SIZE);
var f = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.None);
// Stage 1: get xml file paths
var stage1 = f.StartNew(() => {
try
{
foreach (var phrase in Directory.GetFiles(XML_FOLDER_PATH, "*.xml", SearchOption.TopDirectoryOnly))
{ // build concurrent collection
bufferXmlFileNames.Add(phrase);
}
}
finally
{ // no more additions acceptedin
bufferXmlFileNames.CompleteAdding();
}
});
// Stage 2: ProduceInputXmlDocuments(bufferXmlFileNames, bufferInputXmlDocuments)
var stage2 = f.StartNew(() => {
try
{
foreach (var xmlFileName in bufferXmlFileNames.GetConsumingEnumerable())
{
XmlDocument doc = new XmlDocument();
doc.Load(xmlFileName);
bufferInputXmlDocuments.Add(doc);
}
}
finally
{
bufferInputXmlDocuments.CompleteAdding();
}
});
// Stage 3: PostRequests(BlockingCollection<XmlDocument> xmlDocs, BlockingCollection<HttpWebRequest> posts)
var stage3 = f.StartNew(() => {
try
{
foreach (var xmlDoc in bufferInputXmlDocuments.GetConsumingEnumerable())
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://10.76.22.135/wpaADws/ADService.asmx");
request.ContentType = "text/xml;charset='"utf-8'"";
request.Accept = "text/xml";
request.Method = "POST";
//
Stream stream = request.GetRequestStream();
xmlDoc.Save(stream);
stream.Close();
//
bufferWebRequests.Add(request);
}
}
finally
{
bufferWebRequests.CompleteAdding();
}
});
// Stage 4: ProcessResponses(bufferWebRequests, bufferSoapResults)
var stage4 = f.StartNew(() =>
{
try
{
foreach (var postRequest in bufferWebRequests.GetConsumingEnumerable())
{
HttpWebResponse response = (HttpWebResponse)postRequest.GetResponse();
using (StreamReader rd = new StreamReader(response.GetResponseStream()))
{
string soapResult = rd.ReadToEnd();
bufferSoapResults.Add(soapResult);
}
}
}
finally
{
bufferSoapResults.CompleteAdding();
}
});
// stage 5: update UI
var stage5 = f.StartNew(() =>
{
foreach (var soapResult in bufferSoapResults.GetConsumingEnumerable())
{
Console.WriteLine(soapResult);
}
});
// display blocking collection load state,
// the number of elements in each blocking collection of the pipeline stages
// you can supress this call completely, because it is informational only
var stageDisplay = f.StartNew(
() =>
{
while (true)
{
Console.WriteLine("{0,10} {1,10} {2,10} {3,10}", bufferXmlFileNames.Count, bufferInputXmlDocuments.Count, bufferWebRequests.Count, bufferSoapResults.Count);
//check last stage completion
if (stage5.IsCompleted)
return;
}
}
);
Task.WaitAll(stage1, stage2, stage3, stage4, stage5); //or
//Task.WaitAll(stage1, stage2, stage3, stage4, stage5, stageDisplay);
}
如何使用这样的任务:
List<Task> tasks = new List<Task>(n);
for (int i = 0; i < files.Length; i += n)
{
for (int j = 0; j < n; j++)
{
int x = i + j;
if (x < files.Length && files[x] != null)
{
Task t = new Task(() => function(files[x]));
t.Start();
tasks.Add(t);
}
}
if (tasks.Count > 0)
{
Task.WaitAll(tasks.ToArray(), Timeout.Infinite); // or less than infinite
tasks.Clear();
}
}
我试着在索引上更整洁一些…
另外,注意内循环中的int x = i + j;
很重要,因为c#是如何为lambda捕获变量的。
如果问题是跟踪索引算法,也许使用有意义的名称索引变量?
List<Task> tasks = new List<Task>(taskCount);
for (int filesIdx = 0; filesIdx < files.Length; filesIdx += taskCount)
{
for (int tasksIdx = 0; tasksIdx < taskCount; tasksIdx++)
{
int index = filesIdx + tasksIdx;
if (index < files.Length && files[index] != null)
{
Task task = new Task(() => function(files[index]));
task.Start();
tasks.Add(task);
}
}
if (tasks.Count > 0)
{
Task.WaitAll(tasks.ToArray(), Timeout.Infinite); // or less than infinite
tasks.Clear();
}
}