问题描述
我想重复使用异步HTTP客户端的插座,但我不能够围绕连接到主机的第二次。我基本上把我的异步HTTP客户端作为一个状态机具有以下状态:
I'm trying to reuse a socket in an asynchronous HTTP client, but I'm not able to connect to the host the second time around. I basically treat my asynchronous HTTP client as a state machine with the following states:
- 可用:插槽可供使用
- 连接:套接字连接到终点
- 发送:套接字发送数据到端点
- 接收:套接字从端点接收数据
- 失败:有一个插座故障
- 清理:清理套接字状态
在我所说的连接状态 BeginConnect
:
private void BeginConnect()
{
lock (_sync) // re-entrant lock
{
IPAddress[] addersses = Dns.GetHostEntry(_asyncTask.Host).AddressList;
// Connect to any available address
IAsyncResult result = _reusableSocket.BeginConnect(addersses, _asyncTask.Port, new AsyncCallback(ConnectCallback), null);
}
}
回调方法改变了状态发送
一旦成功建立了连接:
private void ConnectCallback(IAsyncResult result)
{
lock (_sync) // re-entrant lock
{
try
{
_reusableSocket.EndConnect(result);
ChangeState(EClientState.Sending);
}
catch (SocketException e)
{
Console.WriteLine("Can't connect to: " + _asyncTask.Host);
Console.WriteLine("SocketException: {0} Error Code: {1}", e.Message, e.NativeErrorCode);
ThreadPool.QueueUserWorkItem(o =>
{
// An attempt was made to get the page so perform a callback
ChangeState(EClientState.Failed);
});
}
}
}
在清理我关闭
插座和断开连接
与再利用标志:
In the cleanup I Shutdown
the socket and Disconnect
with a reuse flag:
private void CleanUp()
{
lock (_sync) // re-entrant lock
{
// Perform cleanup
if (_reusableSocket.Connected)
{
_reusableSocket.Shutdown(SocketShutdown.Both);
_reusableSocket.Disconnect(true);
}
ChangeState(EClientState.Available);
}
}
到 BeginConnect
导致超时和异常后续调用:
Subsequent calls to BeginConnect
result in a timeout and an exception:
SocketException:连接尝试
失败,因为连接的方没有
一段时间后没有正确响应
时间或建立的连接失败
因为连接主机未能
回应XX.XXX.XX.XX:80
错误code:10060
Error Code: 10060
下面是状态跟踪:
Initializing...
Change State: Connecting
Change State: Sending
Change State: Receiving
Change State: CleanUp
Callback: Received data from client 0 // <--- Received the first data
Change State: Available
Change State: Connecting // <--- Timeout when I try to reuse the socket to connect to a different endpoint
什么我需要做的是能够重复使用的插座连接到不同的主机?
What do I have to do to be able to reuse the socket to connect to a different host?
请注意:我有尝试重新连接到同一个主机,但我假设罢工>同样的事情发生(即无法连接)
Note: I have tried to re-connect to the same host, but the same thing happens (i.e. fails to connect).
更新结果
我发现BeginConnect 的我使用异步家庭调用,而不是开始家庭的呼叫尝试,但我得到了同样的问题!
Update 2.0:
I asked a related question and I tried using the "Async family" calls instead of the "Begin family" calls, but I get the same problem!!!
推荐答案
我谈到了这个问题:what是使用断开连接(真)/ DisconnectEx()
,这可能会帮助你。
I commented on this question: what is benefit from socket reuse in C# about socket reuse using Disconnect(true)/DisconnectEx()
and this may help you.
我个人认为这是一个优化太远客户端code。
Personally I think it's an optimisation too far in client code.
重新更新1到你的问题;不,你会得到一个AbortedOperation异常,如果是这样的话(在这里看到:VB.NET 3.5 SocketException有关部署而不是开发机器)和文档上是错误的,如果你在Vista上运行或更高版本,因为它不执行必须存在线程,直到后重叠I / O完成裁定previous操作系统执行。
Re update 1 to your question; no, you'd get an AbortedOperation exception if that were the case (see here: VB.NET 3.5 SocketException on deployment but not on development machine) and the docs are wrong if you're running on Vista or later as it doesn't enforce the "thread must exist until after overlapped I/O completes" rule that previous operating systems enforce.
正如我已经在答复中链接的问题说,有一个在使用此功能,出站连接建立的非常小的点。这可能是因为它最初被添加到的Winsock API来支持的AcceptEx插座重用()
对入站连接,在那里,一个非常繁忙的Web服务器上使用的TransmitFile()
将文件发送给客户(这是为断开重用似乎起源)。该文档的状态,它不使用它,你开始主动关闭(从而把插座插入连接与
,见这里)并没有真正意义。 TIME_WAIT
等发挥出色TIME_WAIT
As I've already said in the reply to the linked question; there's very little point in using this functionality for outbound connection establishment. It's likely that it was originally added to the Winsock API to support socket reuse for AcceptEx()
on inbound connections, where, on a very busy web server that was using TransmitFile()
to send files to clients (which is where disconnect for reused seems to have originated). The docs state that it doesn't play well with TIME_WAIT
and so using it for connections where you initiate the active close (and thus put the socket into TIME_WAIT
, see here) doesn't really make sense.
你能解释一下为什么你认为这条微优化实际上是必要的,你的情况?
Can you explain why you think this micro optimisation is actually necessary in your case?
这篇关于再利用异步套接字:随后的连接尝试失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!