英文:
C# HttpWebRequest issue: The underlying connection was closed: An unexpected error occurred on a send
问题
我正在制作一个Winforms应用程序,并希望同时发送多个HttpWebRequest
到我的Https API网址(大约20-30个请求),并且总请求数没有限制。然而,在随机时间后,我的Winforms
应用程序遇到问题
错误: 基础连接被关闭: 发生了意外错误
我应该更改我的代码的哪些部分以使我的应用程序正确高效地运行,并且可以无问题地发送多个HttpWebRequest
请求
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12
_tasks = new List<Task>();
cancelSources = new List<CancellationTokenSource>();
foreach (var emailList in smalChunks)
{
CancellationTokenSource cs = new CancellationTokenSource();
Task task = Task.Run(async () =>
{
await HandleEmailList(emailList, userData, cs);
}, cs.Token);
_tasks.Add(task);
cancelSources.Add(cs);
}
await Task.WhenAll(_tasks.ToArray()).ConfigureAwait(false);
下面的函数处理HttpWebRequest
private async Task HandleEmailList(List<SorterResults> emailList, CancellationTokenSource cs)
{
try
{
var sortUrl = "http://localhost:5000/api/xxx";
var httpWebRequest = (HttpWebRequest)WebRequest.Create(sortUrl);
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";
using (var streamWriter = new StreamWriter(await httpWebRequest.GetRequestStreamAsync()))
{
var jsonData = JsonConvert.SerializeObject(emailList.ToArray());
var mailData = $"{{\"mails\":{jsonData}}}";
await streamWriter.WriteAsync(mailData);
}
APIResponseData responseResult;
var httpResponse = (HttpWebResponse)(await httpWebRequest.GetResponseAsync());
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = await streamReader.ReadToEndAsync();
responseResult = JsonConvert.DeserializeObject<APIResponseData>(result);
}
cs.Token.ThrowIfCancellationRequested();
}
catch (Exception ex)
{
//ex.Message: 基础连接被关闭: 发生了意外错误
}
}
英文:
I am making a winforms apps, and I would like to send multiple HttpWebRequest
to my Https API url at same time ( like 20-30 requests) and total request not limited. However after a random time, my Winforms
app runs into issue
error: The underlying connection was closed: An unexpected error occurred on a send
Which parts of my code should I change to make my app run correctly and efficiently, and send multiple HttpWebRequest
requests without issue
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12
_tasks = new List<Task>();
cancelSources = new List<CancellationTokenSource>();
foreach (var emailList in smalChunks)
{
CancellationTokenSource cs = new CancellationTokenSource();
Task task = Task.Run(async () =>
{
await HandleEmailList(emailList, userData, cs);
}, cs.Token);
_tasks.Add(task);
cancelSources.Add(cs);
}
await Task.WhenAll(_tasks.ToArray()).ConfigureAwait(false);
The function bellow handle HttpWebRequest
private async Task HandleEmailList(List<SorterResults> emailList, CancellationTokenSource cs)
{
try
{
ar sortUrl = $"http://localhost:5000/api/xxx";
var httpWebRequest = (HttpWebRequest)WebRequest.Create(sortUrl);
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";
using (var streamWriter = new StreamWriter(await httpWebRequest.GetRequestStreamAsync()))
{
var jsonData = JsonConvert.SerializeObject(emailList.ToArray());
var mailData = $"{{\"mails\":{jsonData}}}";
await streamWriter.WriteAsync(mailData);
}
APIResponseData responseResult;
var httpResponse = (HttpWebResponse)(await httpWebRequest.GetResponseAsync());
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = await streamReader.ReadToEndAsync();
responseResult = JsonConvert.DeserializeObject<APIResponseData>(result);
}
cs.Token.ThrowIfCancellationRequested();
}
catch (Exception ex)
{
//ex.Message: The underlying connection was closed: An unexpected error occurred on a send
}
}
答案1
得分: 1
请确认内部任务是否运行了。
在这一行上设置断点,看看它是否被执行:
cs.Token.ThrowIfCancellationRequested()
我怀疑可能是因为使用块释放了流写入器时,它也释放了流,从而关闭了连接。我建议更改Visual Studio中的异常设置,以在发生异常时中断,然后您可以进一步进行调查。
另外,请告诉我您没有在建立电子邮件僵尸网络吧!
以下是一些额外的未经请求的建议:
当一个方法接受一个IEnumerable
时,不要调用_tasks.ToArray()
,将其作为列表传递,这样可以提高应用程序的性能。
为什么要创建多个CancellationTokenSource
对象?您是否可以只创建一个,然后将令牌传递下去?
为什么要使用匿名的Task.Run
委托来转发任务?您有一个返回任务的函数,所以您可以将其添加到列表中。
使用这些更改:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12
_tasks = new List<Task>();
CancellationTokenSource cs = new CancellationTokenSource();
foreach (var emailList in smalChunks)
{
Task task = HandleEmailList(emailList, userData, cs);
_tasks.Add(task);
}
await Task.WhenAll(_tasks).ConfigureAwait(false);
还要更改任务函数的签名:
private async Task HandleEmailList(List<SorterResults> emailList, CancellationToken ct)
英文:
Can you confirm if the internal task runs at all?
Stick a breakpoint on this line and see if it is ever hit:
cs.Token.ThrowIfCancellationRequested()
I suspect it could be something like when your using block disposes of the stream writer, it also disposes the stream and this closes the connection. I'd change the exception settings in visual studio to break on whatever the exception type is, then you can interrogate this further.
Also, please tell me you aren't building an email botnet!
Here's some additional unsolicited advice:
Don't call _tasks.ToArray()
when a method takes an IEnumerable
, it's fine as a list and that translation just slows your application down
Why are you creating multiple CancellationTokenSource
objects? Could you just create a single one, then pass the token down?
Why are you forwarding the task with an anonymous Task.Run
delegate? You have a function that returns a task, so can't you just add that to the list?
With these changes:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12
_tasks = new List<Task>();
CancellationTokenSource cs = new CancellationTokenSource();
foreach (var emailList in smalChunks)
{
Task task = HandleEmailList(emailList, userData, cs);
_tasks.Add(task);
}
await Task.WhenAll(_tasks).ConfigureAwait(false);
Also change the signature of the task function
private async Task HandleEmailList(List<SorterResults> emailList, CancellationToken ct)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论