在 Web 应用程序中设置 WCF TCP 服务

Posted

技术标签:

【中文标题】在 Web 应用程序中设置 WCF TCP 服务【英文标题】:Setting up WCF TCP service in a web application 【发布时间】:2013-05-13 18:19:16 【问题描述】:

我已经为此奋斗了好几天,实际上浏览了一百篇文章,提供了有关如何在 Web 应用程序中设置基于 WCF TCP 的服务的部分指南。如果有人可以帮助我,我会将这个问题变成一个完整的指南。

当前状态

net.tcp 连接在我的开发机器上工作。在部署到 Windows Server 2008 R2 后,它也可以在本地工作。但是,它不能远程工作,即使可以远程 telnet 到服务器上的 808 端口。滚动到问题的底部以获取详细信息。如果可以的话,请帮忙。

我将为这个详细信息创建一个新问题,如果我从中得到结果,我会用答案更新这个问题。

代码

我创建了ServerHubService.svc,内容如下:

namespace Manage.SignalR

    [ServiceContract]
    public class ServerHubService
    
        [OperationContract]
        public void UpdateServerStatus(string serverStatus)
        
            // Do something
        
    

托管服务的应用程序配置

按照在线教程,我在我的 Web.config 中添加了以下内容(我尝试了许多不同的变体)。这是托管服务的 Web 应用程序的 Web.config,稍后我想通过 TCP 连接。

<configuration>
  <system.serviceModel>
    <services>
      <service behaviorConfiguration="ServerHubBehavior"
      name="Manage.SignalR.ServerHubService">
        <endpoint address=""
              binding="netTcpBinding"
              bindingConfiguration="portSharingBinding"
              name="MyServiceEndpoint"
              contract="Manage.SignalR.ServerHubService">
          <identity>
            <dns value="localhost" />
          </identity>
        </endpoint>

        <endpoint address="mex"
              binding="mexTcpBinding"
              bindingConfiguration=""
              name="MyServiceMexTcpBidingEndpoint"
              contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="net.tcp://test.mydomain.com:808/SignalR/ServerHubService.svc" />
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="ServerHubBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="false" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <bindings>
      <netTcpBinding>
        <binding name="portSharingBinding" portSharingEnabled="true"/>
      </netTcpBinding>
    </bindings>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true"
      minFreeMemoryPercentageToActivateService="0" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
</configuration>

httpGetEnabled="true" 很重要,否则您无法创建对该服务的服务引用。

运行 Web 应用程序的服务器配置

我在装有 IIS 7.5 的开发机器上进行设置

我读到 IIS Express(内置于 Visual Studio)不支持 net.tcp,所以我使用 .NET 4.5 在 IIS 7.5 中建立了一个新网站,并且它具有 net.tcp 绑定

我还去了网站的高级设置并将启用的协议设置为http,net.tcp

我确保 Windows 功能非 HTTP 激活已启用(并重新启动)。这是一项 Windows 功能,因此请查找“打开或关闭 Windows 功能”来找到它。

确认网络应用程序正在运行

该网站适用于 Web 应用程序的其余部分。我将 test.mydomain.com 设置为指向我的 hosts 文件中的 127.0.0.1。我什至可以访问http://test.mydomain.com/SignalR/ServerHubService.svc,它会向我展示一个从 .NET 自动生成的漂亮页面,解释如何使用此服务。

到目前为止一切顺利。

.NET 生成的页面告诉我使用这个地址来生成到我的服务的连接:

net.tcp://computername/SignalR/ServerHubService.svc/mex

尝试作为客户端连接到服务

如果您不记得设置httpGetEnabled="true",则在尝试创建对其的服务引用时会出错。如果您使用 WCF 测试客户端(也是 Visual Studio 中包含的工具)并且未设置 httpGetEnabled,您将收到如下错误:

错误:无法从 net.tcp://computername/SignalR/ServerHubService.svc/mex

如果这是您使用的 Windows (R) Communication Foundation 服务 有访问权限,请检查您是否已在以下位置启用元数据发布 指定的地址。如需帮助启用元数据发布,请 请参阅 MSDN 文档 http://go.microsoft.com/fwlink/?LinkId=65455.WS-Metadata

交换错误 URI: net.tcp://computername/SignalR/ServerHubService.svc/mex 元数据 包含无法解析的引用: 'net.tcp://computername/SignalR/ServerHubService.svc/mex'。不能 连接到 net.tcp://computername/SignalR/ServerHubService.svc/mex。 连接尝试持续了 00:00:04.0032289 的时间跨度。

TCP 错误代码 10061:无法建立连接,因为目标 机器主动拒绝它 [2001:0:4137:9e76:c81:a4c:a547:b2fd]:808。 由于目标机器主动,无法建立连接 拒绝它 [2001:0:4137:9e76:c81:a4c:a547:b2fd]:808

但是,如果您已完成上述所有操作,您应该能够添加对服务的引用。

服务中的调用方法

当尝试从 WCF 测试客户端调用服务中的简单 Hello World 方法时,它返回以下错误:

无法连接到 net.tcp://计算机名/SignalR/ServerHubService.svc。连接 尝试持续了 00:00:04.0002288 的时间跨度。 TCP错误代码 10061: 由于目标机器主动,无法建立连接 拒绝了。

这是包含在错误中的内部堆栈跟踪:

无法建立连接,因为目标机器主动 拒绝它 [2001:0:5ef5:79fb:3884:a:a547:b2fd]:808 at System.Net.Sockets.Socket.DoConnect(端点 endPointSnapshot, SocketAddress socketAddress) 在 System.Net.Sockets.Socket.Connect(EndPoint remoteEP) 在 System.ServiceModel.Channels.SocketConnectionInitiator.Connect(Uri uri,TimeSpan 超时)

如果您使用netstat -an |find /i "listening" 看到端口 808 上没有任何监听,可能是因为 Net.Tcp Listener Adapter 服务没有运行。

确认

呼叫现在进行,但需要进行一些确认才能宣布成功。我需要确认这实际上是对端口 808 的 net.tcp 调用,而不是对 http 端点的调用。我正在尝试使用 Wireshark 执行此操作,但它没有显示出来,可能是因为它是来自我的本地计算机的呼叫。

部署

要克服的最后一个挑战是将其部署在 Web 服务器上,确保在开发机器上工作的东西也能在 Web 服务器上工作。

发布到 Windows Server 2008 R2 后它不起作用。它给出了常见的SocketException: An existing connection was forcibly closed by the remote host

它在服务器本地运行良好,但它不能在远程运行。

这是用于检查服务器的清单:

Net.Tcp Listener Adapter 服务是否正在运行?是的 绑定到net.tcp 的IIS 站点是否设置为808:*?是的 IIS 中站点的高级设置下的启用协议是否设置为http,net.tcp?是的 服务器是否在监听 808 端口?是的,通过netstat -an |find /i "listening" 确认 防火墙中是否打开了 808 端口?是的。 服务器上的防火墙已关闭。 我可以用telnet mydomain.com 808从外部远程登录到服务器的808端口 在服务器上的服务配置中,确认如下: baseAddress 调整为net.tcp://mydomain.com:808/SignalR/ServerHubService.svc 之前是localhost,但在服务器上不起作用后更改为mydomain.com&lt;identity&gt;&lt;dns value="mydomain.com" /&gt;&lt;/identity&gt; 已经在服务器本地和另一台服务器上使用客户端进行了测试。两者都可以通过 telnet 连接到端口 808,并且都给出相同的错误消息。

服务器上可能缺少哪些配置?我离目标如此之近。请协助我解决此问题并完成问题。

这是调用服务的服务器上的客户端配置:

<system.serviceModel>
  <bindings>
    <netTcpBinding>
      <binding name="MyServiceEndpoint" />
    </netTcpBinding>
  </bindings>
  <client>
    <endpoint address="net.tcp://mydomain.com:808/SignalR/ServerHubService.svc"
      binding="netTcpBinding" bindingConfiguration="MyServiceEndpoint"
      contract="ServerHubService.ServerHubService" name="MyServiceEndpoint">
      <identity>
        <dns value="mydomain.com" />
      </identity>
    </endpoint>
  </client>
</system.serviceModel>

我也尝试在端点中不配置 808,因为据传这是 net.tcp 连接的默认端口。但是,它仍然给出相同的结果。

与其随机尝试很多事情,不如提出一个好问题:如何调试这样的事情? 我可以在任一服务器上安装一个程序来准确告诉我为什么这个呼叫被阻止了吗?

使用这样配置的 Wireshark,可以查看端口 808 上到达服务器的调用,并可能确定调用不起作用的原因。但是,我目前不知道如何分析。

祝你好运

我放弃了,而是在套接字层实现了这一点。它立即起作用。不过,我希望这可以帮助其他人。我正在设置一个答案,因为许多问题都已解决,并且最终在本地工作,所以任何剩余的问题都可能与我的特定环境有关。

【问题讨论】:

您是否启用了 WCF 非 HTTP 激活组件? (详情在这里msdn.microsoft.com/en-us/library/ms731053.aspx)。您是否还为您的网站添加了 tcp 到允许的协议? (管理网站 -> 高级设置 -> 启用协议)。您是否尝试过基于通过 HTTP 公开的元数据生成代理? (test.mydomain.com/SignalR/ServerHubService.svc) 我忘记启用非 HTTP 激活(我只在我的测试服务器上做过)。不幸的是,启用此功能后我得到了同样的错误。我已经记住了高级设置下的 net.tcp,但现在已将其添加到问题详细信息中。如果我尝试基于 http 生成代理,我会收到一个有趣的错误 - 我将用这个更新问题。 【参考方案1】:

您必须根据通过 HTTP 为 tcp 公开的元数据生成代理。(确保 httpGetEnabled 设置为 true)。您在客户端使用的地址应该是托管地址。请参考下面的帖子。

http://blogs.msdn.com/b/swiss_dpe_team/archive/2008/02/08/iis-7-support-for-non-http-protocols.aspx

【讨论】:

啊,我实际上在“ServiceHubBehavior”中有 httpGetEnabled=false。我会尝试编辑它,看看它是否有所作为。谢谢。 成功了。现在可以从 WCF 测试客户端添加它并从我的实际客户端创建服务引用......实际调用仍然不起作用,但我会用它来更新问题...... 尝试使用 TCP mex 地址 (net.tcp://computername/SignalR/ServerHubService.svc) 而不是 http 创建服务代理。如果成功添加服务引用,则方法调用也应该工作。从上面的错误可以看出服务没有监听808端口。检查你在IIS中创建的站点的TCP协议的端口号。 我尝试使用 net.tcp 地址来创建服务引用,在 url 中有和没有 :808。但是您可能正在做某事,因为我运行了netstat -an |find /i "listening",发现端口 808 上没有任何东西在监听 如果它在本地工作正常,那么您的服务器配置应该没有任何问题。确保您的客户端指向正确的 url(net.tcp://mydomain.com:808/SignalR/ServerHubService.svc) 而不是 localhost 一个。端口号可能包含也可能不包含,因为 808 是默认值net.tcp 的端口。【参考方案2】:

在您的问题中,您提到您连接到“test.mydomain.com”,但错误将服务器更改为“计算机名”。然后在您的评论中您提到它仍然无法连接。如果您希望在 WSDL/MEX 中返回别名,请在您的服务行为中添加 useRequestHeadersForMetadataAddress 节点。这里是这个节点的 MSDN 信息:MSDN useRequestHeadersForMetadataAddress node

这就是您的配置的外观。这考虑了 Prasath 给出的答案 (httpGetEnabled="true")。

<serviceBehaviors>
   <behavior name="ServerHubBehavior">
      <serviceMetadata httpGetEnabled="true" />
      <serviceDebug includeExceptionDetailInFaults="false" />
      <useRequestHeadersForMetadataAddress>
         <defaultPorts>
            <add scheme="net.tcp" port="808" />
         </defaultPorts>
      </useRequestHeadersForMetadataAddress>
   </behavior>
</serviceBehaviors>

【讨论】:

这不会导致任何明显的差异。这样做之后,当我运行 WCF 测试客户端时,结果是一样的:它找到了服务,但无法调用它,并且错误消息显示它正在尝试调用 computername【参考方案3】:

在 IIS 中托管基于 TCP 的服务一直是个难题。 WCF 使运行您自己的服务主机、侦听您的 TCP 端口变得非常容易。我的建议是这样做并将其设置为作为 Windows 服务运行。

见这篇文章:http://msdn.microsoft.com/en-us/library/ff649818.aspx

【讨论】:

这在我的场景中是不可能的,它必须是一个 Web 应用程序。 或者也可以让Web应用自己托管WCF服务? 你看过这个博客吗? blogs.msdn.com/b/prathul/archive/2011/11/28/… 我经历过。我做了博客中提到的所有事情。【参考方案4】:

我猜您遇到的问题是您需要为您的 WCF 服务(在计算机上)设置 SPN(服务主体名称)并将其添加到运行该服务的服务帐户中。

如果您在默认应用程序池用户下运行它,那么您需要为机器配置 SPN。

我知道这很麻烦,而且通常是在我们的服务准备好部署到生产或预生产环境后等待我们开发人员的惊喜。

SPN 由 Kerberos 在身份验证过程中使用。

尝试使用机器的 IP 而不是主机名来解析您的服务。 (这不应该需要 SPN),将“test.mydomain.com”替换为机器 IP 地址:

<host>
    <baseAddresses>
        <add baseAddress="net.tcp://192.168.0.253:808/SignalR/ServerHubService.svc" />
    </baseAddresses>
</host>

看看这些文章: - Kerberos for the Busy Admin - WCF on intranet with windows authentication - 对于以下帖子,请尝试阅读不被接受为答案的帖子:What SPN do I need to set for a net.tcp service?

【讨论】:

注意,我不是在服务中托管 WCF,而是在 Web 应用程序中。应用程序池实际上是作为服务器上的本地管理员运行的。我已尝试按照您的建议将 baseAddress 设置为 IP 地址,但没有成功。 关于 Kerberos 和 Windows 身份验证:我很惊讶这应该是必要的,因为我没有启用这些功能。但我会尝试与 SPN 合作,看看是否有帮助。 再次阅读您的问题,我认为我的建议可能不相关。随意忽略。无论如何,为了讨论的完整性,我会留下它。 感谢您的跟进,Ashraf ...您还有其他建议吗?【参考方案5】:

您是否尝试在本地计算机上的 Windows 服务中托管服务(用于测试目的)?这样,您至少会知道问题出在服务端还是 IIS/服务器配置。

【讨论】:

它实际上可以在我的本地机器上运行。当前的问题在于服务器上的部署。【参考方案6】:

我猜你在服务器上有Net.TCP Port sharing service running...还没有找到明确说明。

【讨论】:

是的,我确实有这个运行。我将在问题中添加该细节。谢谢。 另外,我假设您在双方都使用相同的安全设置(您问题中的示例不是实际的真实代码)。 我刚刚发现一篇有趣的文章说如果你设置了 net.tcp iis 绑定,但它仍然无法工作holsson.wordpress.com/2009/09/24/… 然后手动设置它:) 还有一个有趣的评论:“如果它是808:* 您的服务可以在 net.tcp://localhost/MyServices/Service1.svc 下访问,例如在没有端口限定符的默认地址上。 谢谢。我的问题中的示例非常接近真实代码。我在服务器或环境中没有防火墙,这一定是我可以远程 telnet 到端口 808 的原因。 808 作为 net.tcp 的“默认”端口非常有趣,我一定会尝试在端点中不使用 808 关于安全性,我打算在没有任何安全性的情况下运行,只是为了让它运行起来。【参考方案7】:

我今天在这里遇到了类似的问题,同时从 asp.net web api 中调用 net.tcp wcf 服务。我不会说从所有其他机器上这项服务已经工作了多年,但是调用是 wcf 自托管,wcf iis asp.net 兼容性托管 -> 针对 net.tcp 服务自托管。当我发布调用相同 net.tcp 服务的简单 Web api 时,一切都出错了,所有连接都无缘无故中止,即使是跟踪双方(服务和客户端)的完整 wcf 也没有帮助,只是告诉相同“连接中止”。

我已经知道 net.tcp 启用了传输安全性,使用 Windows 身份验证对通信进行签名和加密,所以,我只是尝试关闭安全性,一切都开始正常工作。

试一试以这种方式关闭双方(客户端和服务)的安全性:

<security mode="None"/>

完整的服务绑定:

<netTcpBinding>

    <binding name="netTcpBinding" portSharingEnabled="true">

        <security mode="None"/>

    </binding>

</netTcpBinding>

我希望这对你也有帮助。

【讨论】:

以上是关于在 Web 应用程序中设置 WCF TCP 服务的主要内容,如果未能解决你的问题,请参考以下文章

在 wcf 服务中设置 cookie

在 sharepoint 中设置流式 WCF 服务

在 WCF 服务中设置绑定

使用 WCF over Http 和 Https 调用 Web 服务

Confluence 6 外部小工具在其他应用中设置可信关系

为 WCF 服务添加多个 HTTP 基地址