2011-04-23 212 views
7

我试图在异步HTTP客户端中重用套接字,但我无法第二次连接到主机。我基本上把我的异步HTTP客户端状态机具有以下状态:重用异步套接字:后续连接尝试失败

  • 可用:插座可供使用
  • 连接:将插座连接到端点
  • 发送:套接字发送数据到端点
  • 接收:插座从端点
  • 无法接收数据:有一个插座故障
  • 清理:清理套接字状态

在连接状态下我打电话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); 
    } 
} 

回调方法改变状态Sending一次成功的连接已经建立:

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); 
      }); 
     } 
    } 
} 

在我Shutdown的清理插座和Disconnect带重用标记:

在超时

后续调用BeginConnect结果和例外:

SocketException:连接尝试 失败,因为连接的方没有 一段 时间后没有正确答复或建立的连接失败 因为连接主机未能响应 XX.XXX.XX.XX:80

错误代码: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 

什么我必须做的,以便能够重新使用套接字连接到不同的主机?

注意:我有 而不是 试图重新连接到同一主机,但 我假设 发生同样的事情(即无法连接)。

更新
我发现下面的音符在documentation of BeginConnect

如果此套接字之前已断开连接,然后BeginConnect必须在一个线程,将不会退出,直到操作完成调用。这是底层提供商的限制。此外,使用的EndPoint必须不同。

我开始怀疑我的问题是否与该问题有关...我正在连接到不同的EndPoint,但它们是什么意思,我们称之为BeginConnect的线程在操作完成之前不能退出?

更新2.0:
我问了related question,我尝试使用“异步家庭”调用,而不是“开始家庭”电话,但我得到了同样的问题!

回答

2

我对此问题发表了评论:what is benefit from socket reuse in C#关于使用套接字重复使用Disconnect(true)/DisconnectEx()这可能对您有所帮助。

个人而言,我认为这是客户端代码中的一项优化。

重新更新1到您的问题;不,你会得到一个AbortedOperation异常,如果是这种情况(见这里:VB.NET 3.5 SocketException on deployment but not on development machine)和文档是错误的,如果你在Vista或更高版本上运行,因为它不强制执行“线程必须存在,直到重叠的I/O完成“规则,以前的操作系统强制执行。

正如我在回复链接问题时所说的那样;使用此功能进行出站连接建立几乎没有意义。它很可能是最初添加到Winsock API以支持入站连接上的AcceptEx()的套接字重用,其中在使用TransmitFile()向客户端发送文件的非常繁忙的Web服务器上(这是发生断开连接似乎已经发生的地方) 。该文档声明它不能很好地与TIME_WAIT配合使用,因此将它用于启动主动关闭(因此将套接字放入TIME_WAIT,请参阅here)的连接并没有什么意义。

你能解释一下为什么你认为这种微型优化在你的情况下实际上是必要的吗?

+0

我不知道为什么我没有回答你的问题,但我做这种微型优化的原因是因为我每秒抓取300多个网页,每次抓取都要求我关闭旧套接字,处置它并打开一个新套接字。该应用程序运行时间很长,因此最终会导致内存抖动并降低系统速度。性能是这种情况下的关键。 – Kiril 2011-11-24 06:24:44

0
+0

它看起来像'NetTcpBinding'是一个WCF的东西,我使用原始的'套接字'...我没有看到我怎么可以利用'NetTcpBinding'与原始的'套接字'。 – Kiril 2011-04-27 11:58:23

+0

ups。我认为这是一样的。我通常把它放到应用程序配置是这样的:<?XML版本= “1.0”?> <结构> <添加地址= “*” MAXCONNECTION = “32768”/> NickD 2011-04-27 13:05:04

+0

我不认为套接字受这些设置的影响。许多套接字应用甚至可能没有app.config,但感谢您的答案:)。 – Kiril 2011-04-27 13:10:49