简体   繁体   English

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

[英]Setting up WCF TCP service in a web application

I've been battling with this for days, literally going through a hundred articles giving partial guidelines on how to set up a WCF TCP based service in a web application. 我已经和它斗争了好几天,实际上经历了一百篇文章,给出了如何在Web应用程序中设置基于WCF TCP的服务的部分指导。 If someone can help me, I will make this question into a complete guideline. 如果有人可以帮助我,我会将这个问题变成一个完整的指南。

Current status 当前状态

The net.tcp connection works on my development machine. net.tcp连接适用于我的开发机器。 It also works locally after being deployed to a Windows Server 2008 R2. 它在部署到Windows Server 2008 R2后也可在本地运行。 However, it doesn't work remotely, even though it's possible to telnet to port 808 on the server remotely. 但是,它不能远程工作,即使可以远程telnet到服务器上的端口808。 Scroll to the bottom of the question for details. 滚动到问题的底部以获取详细信息。 Please help if you can. 如果可以的话请帮忙。

I will create a new question for this detail and update this question with the answer if I get a result out of it. 我将为此详细信息创建一个新问题,如果我从中得到结果,则用答案更新此问题。

Code

I created ServerHubService.svc with the following content: 我创建了ServerHubService.svc其中包含以下内容:

namespace Manage.SignalR
{
    [ServiceContract]
    public class ServerHubService
    {
        [OperationContract]
        public void UpdateServerStatus(string serverStatus)
        {
            // Do something
        }
    }
}

Configuration of the application hosting the service 托管服务的应用程序的配置

Following an online tutorial, I added the following to my Web.config (I tried MANY different variations). 在线教程之后,我在Web.config中添加了以下内容(我尝试了很多不同的变体)。 This is the Web.config of the web application hosting the service that I later want to connect to with TCP. 这是托管该服务的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" is important because otherwise you cannot create a service reference to the service. httpGetEnabled="true"很重要,否则您无法创建对服务的服务引用。

Configuration of the server where the web application is running 配置运行Web应用程序的服务器

I am setting this up on my development machine which has IIS 7.5 我在我的具有IIS 7.5的开发机器上进行设置

I read that IIS Express (built into Visual Studio) doesn't support net.tcp, so I set up a new website in IIS 7.5 using .NET 4.5 and that has a net.tcp binding 我读到IIS Express(内置于Visual Studio中)不支持net.tcp,因此我使用.NET 4.5在IIS 7.5中设置了一个新网站并且具有net.tcp绑定

IIS中的绑定

I also went to Advanced Settings for the website and set Enabled Protocols to http,net.tcp 我还进入了网站的高级设置,并将Enabled Protocols设置为http,net.tcp

I ensured that the Windows Feature Non-HTTP Activation is enabled (and restarted). 我确保启用(并重新启动)Windows功能非HTTP激活。 It's a Windows Feature so look for "Turn Windows features on or off" to find this. 这是一个Windows功能,所以寻找“打开或关闭Windows功能”来找到它。

在此输入图像描述

Confirming the web application is running 确认Web应用程序正在运行

The website works fine for the rest of the web application. 该网站适用于其余的Web应用程序。 I set up test.mydomain.com to point to 127.0.0.1 in my hosts file. 我在我的hosts文件中设置test.mydomain.com指向127.0.0.1。 I can even visit http://test.mydomain.com/SignalR/ServerHubService.svc and it will show me a nice auto generated page from .NET, explaining how to use this service. 我甚至可以访问http://test.mydomain.com/SignalR/ServerHubService.svc ,它将向我展示一个很好的自动生成的.NET页面,解释如何使用这项服务。

So far so good. 到现在为止还挺好。

The page generated by .NET tells me to use this address to generate a connection to my service: .NET生成的页面告诉我使用此地址生成与我的服务的连接:

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

Trying to connect to the service as a client 尝试以客户端身份连接到服务

If you do not remember to set httpGetEnabled="true" you will get an error when trying to create a service reference to it. 如果您不记得设置httpGetEnabled="true" ,则在尝试创建服务引用时会出现错误。 If you use the WCF Test Client (also a tool included in Visual Studio) and didn't set httpGetEnabled, you will get an error like the following: 如果您使用WCF测试客户端(也是Visual Studio中包含的工具)并且未设置httpGetEnabled,则会出现如下错误:

Error: Cannot obtain Metadata from net.tcp://computername/SignalR/ServerHubService.svc/mex 错误:无法从net.tcp获取元数据://computername/SignalR/ServerHubService.svc/mex

If this is a Windows (R) Communication Foundation service to which you have access, please check that you have enabled metadata publishing at the specified address. 如果这是您有权访问的Windows(R)Communication Foundation服务,请检查您是否已在指定地址启用元数据发布。 For help enabling metadata publishing, please refer to the MSDN documentation at http://go.microsoft.com/fwlink/?LinkId=65455.WS-Metadata 有关启用元数据发布的帮助,请参阅MSDN文档, 网址http://go.microsoft.com/fwlink/?LinkId=65455.WS-Metadata

Exchange Error URI: net.tcp://computername/SignalR/ServerHubService.svc/mex Metadata contains a reference that cannot be resolved: 'net.tcp://computername/SignalR/ServerHubService.svc/mex'. Exchange错误URI:net.tcp://computername/SignalR/ServerHubService.svc/mex元数据包含无法解析的引用:'net.tcp://computername/SignalR/ServerHubService.svc/mex'。 Could not connect to net.tcp://computername/SignalR/ServerHubService.svc/mex. 无法连接到net.tcp://computername/SignalR/ServerHubService.svc/mex。 The connection attempt lasted for a time span of 00:00:04.0032289. 连接尝试持续时间跨度为00:00:04.0032289。

TCP error code 10061: No connection could be made because the target machine actively refused it [2001:0:4137:9e76:c81:a4c:a547:b2fd]:808. TCP错误代码10061:无法建立连接,因为目标计算机主动拒绝它[2001:0:4137:9e76:c81:a4c:a547:b2fd]:808。 No connection could be made because the target machine actively refused it [2001:0:4137:9e76:c81:a4c:a547:b2fd]:808 没有连接,因为目标机器主动拒绝它[2001:0:4137:9e76:c81:a4c:a547:b2fd]:808

However, if you've done everything as above, you should be able to add a reference to the service. 但是,如果您已完成上述所有操作,则应该能够添加对服务的引用。

Calling methods in the service 在服务中调用方法

When trying to call a simple Hello World method in the service from the WCF Test Client, it returns the following error: 尝试从WCF测试客户端调用服务中的简单Hello World方法时,它返回以下错误:

Could not connect to net.tcp://computername/SignalR/ServerHubService.svc. 无法连接到net.tcp://computername/SignalR/ServerHubService.svc。 The connection attempt lasted for a time span of 00:00:04.0002288. 连接尝试持续时间跨度为00:00:04.0002288。 TCP error code 10061: No connection could be made because the target machine actively refused it. TCP错误代码10061:无法建立连接,因为目标计算机主动拒绝它。

This is inner stacktrace that is included in with the error: 这是包含在错误中的内部堆栈跟踪:

No connection could be made because the target machine actively refused it [2001:0:5ef5:79fb:3884:a:a547:b2fd]:808 at System.Net.Sockets.Socket.DoConnect(EndPoint endPointSnapshot, SocketAddress socketAddress) at System.Net.Sockets.Socket.Connect(EndPoint remoteEP) at System.ServiceModel.Channels.SocketConnectionInitiator.Connect(Uri uri, TimeSpan timeout) 无法建立连接,因为目标计算机在System.Net.Sockets.Socket.DoConnect(EndPoint endPointSnapshot,SocketAddress socketAddress)处主动拒绝它[2001:0:5ef5:79fb:3884:a:a547:b2fd]:808 System.ServiceModel.Channels.SocketConnectionInitiator.Connect(Uri uri,TimeSpan timeout)中的.Net.Sockets.Socket.Connect(EndPoint remoteEP)

If you use netstat -an |find /i "listening" to see that nothing is listening on port 808, it's probably because the Net.Tcp Listener Adapter service is not running. 如果使用netstat -an |find /i "listening"来查看端口808上没有任何内容正在侦听,则可能是因为Net.Tcp侦听器适配器服务未运行。

Confirmation 确认

The call goes through now, but some confirmation is needed before it can be declared a success. 这个电话现在已经过去,但在宣布成功之前需要一些确认。 I need to confirm that this is in fact net.tcp call on port 808 and not actually a call on the http endpoint. 我需要确认这实际上是端口808上的net.tcp调用,而不是http端点上的实际调用。 I am trying to do this with Wireshark, but it doesn't show up, probably because it's a call happening from and to my local machine. 我试图用Wireshark做这个,但它没有出现,可能是因为它是从本地机器发出的呼叫。

Deployment 部署

The last challenge to conquer would be to deploy this on a web server, ensuring that what works on the development machine, also works on the web server. 征服的最后一个挑战是将其部署在Web服务器上,确保在开发机器上运行的是什么,也可以在Web服务器上运行。

It doesn't work after publish to a Windows Server 2008 R2. 发布到Windows Server 2008 R2后,它不起作用。 It gives the common SocketException: An existing connection was forcibly closed by the remote host . 它给出了常见的SocketException: An existing connection was forcibly closed by the remote host

It works well locally on the server, but it doesn't work remotely. 它在服务器上本地运行良好,但它不能远程工作。

Here is the checklist used to check the server: 以下是用于检查服务器的清单:

  • Is the Net.Tcp Listener Adapter service running? Net.Tcp Listener Adapter服务是否正在运行? Yes
  • Is the IIS site binding to net.tcp set to 808:* ? IIS网站绑定到net.tcp设置为808:* Yes
  • Is Enabled Protocols under Advanced Settings for the site in IIS set to http,net.tcp ? IIS的站点的高级设置下的启用协议是否设置为http,net.tcp Yes
  • Is the server listening on port 808? 服务器是否在端口808上侦听? Yes, checked with netstat -an |find /i "listening" 是的,用netstat -an |find /i "listening"查看
  • Is a port 808 open in the firewall? 防火墙是否打开808端口? Yes. 是。
    • Firewall is turned off on the server. 防火墙在服务器上关闭。
    • I can telnet to the server on port 808 from outside with telnet mydomain.com 808 我可以通过telnet mydomain.com 808从外部telnet mydomain.com 808登录到端口808上的服务器
  • In the configuration of the service on the server, the following was confirmed: 在服务器上的服务配置中,确认了以下内容:
    • baseAddress is adjusted to net.tcp://mydomain.com:808/SignalR/ServerHubService.svc baseAddress调整为net.tcp://mydomain.com:808/SignalR/ServerHubService.svc
    • This was localhost before, but changed to mydomain.com after it didn't work on the server: <identity><dns value="mydomain.com" /></identity> 这之前是localhost ,但在服务器上无法运行后更改为mydomain.com<identity><dns value="mydomain.com" /></identity>
  • It has been tested with a client locally on the server and on another server. 它已在服务器和另一台服务器上本地客户端进行了测试。 Both can connect to port 808 with telnet and both give the same error message. 两者都可以使用telnet连接到端口808,并且都提供相同的错误消息。

What configuration could be missing on the server? 服务器上可能缺少哪些配置? I am so close to the goal. 我非常接近目标。 Please assist me in troubleshooting this and complete the question. 请协助我解决此问题并完成问题。

Here is the client configuration on the server calling the service: 以下是调用服务的服务器上的客户端配置:

<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>

I also tried without 808 configured in the endpoint, as this is rumored to be the default port for net.tcp connections. 我也尝试在端点中没有配置808,因为据传这是net.tcp连接的默认端口。 However, it still gives the same result. 但是,它仍然给出了相同的结果。

Instead of trying lots of things randomly, the good question is perhaps: How does one debug something like this? 而不是随意尝试很多东西,好的问题可能是:如何调试这样的东西? Can I install a program on either server that will tell me exactly WHY this call is being blocked? 我可以在任一服务器上安装一个程序,它会告诉我为什么这个电话被阻止了?

With Wireshark configured like this, it's possible to look at the call coming to the server on port 808 and possibly determine why the call doesn't work. 通过这样配置的Wireshark,可以查看端口808上到达服务器的呼叫,并可能确定呼叫无效的原因。 However, I have no idea how to analyze this at present time. 但是,我不知道目前如何分析这个问题。

Wireshark的

Good luck 祝好运

I gave up and implemented this in the socket layer instead. 我放弃了并在套接字层实现了这一点。 It worked immediately. 它立即起作用。 I hope this can help someone else, though. 不过,我希望这可以帮助别人。 I'm setting an answer because many of the issues were solved and it did work locally eventually, so any problem remaining is probably related to me specific environment. 我正在设置答案,因为许多问题已经解决,最终在本地工作,所以剩下的任何问题都可能与我的具体环境有关。

You have to generate the Proxy based on the metadata exposed over HTTP for tcp.(make sure httpGetEnabled is set to true). 您必须基于通过HTTP为tcp公开的元数据生成代理(确保httpGetEnabled设置为true)。 The address you use at the client should be the hosted address. 您在客户端使用的地址应该是托管地址。 Please refer the below post. 请参考以下帖子。

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

In your question you mentioned that you connected to "test.mydomain.com" but the error changed the server to "computername". 在您的问题中,您提到您已连接到“test.mydomain.com”但错误已将服务器更改为“computername”。 Then in your comment you mentioned it still failing to connect. 然后在你的评论中你提到它仍然无法连接。 If you wish to have the alias returned in the WSDL/MEX Add the useRequestHeadersForMetadataAddress node in your service behavior. 如果您希望在WSDL / MEX中返回别名,请在服务行为中添加useRequestHeadersForMetadataAddress节点。 Here is the MSDN information on this node: MSDN useRequestHeadersForMetadataAddress node 以下是此节点上的MSDN信息: MSDN useRequestHeadersForMetadataAddress节点

This is how your config should look. 这是您的配置应该如何。 This takes into account answer given by Prasath (httpGetEnabled="true"). 这考虑了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>

Hosting a TCP Based service in IIS has always been a bear. 在IIS中托管基于TCP的服务始终是一个负担。 WCF makes it very easy to run your own service host, listening on your TCP port. WCF使您可以非常轻松地运行自己的服务主机,监听TCP端口。 My recommendation would be to do that and set it up to run as a Windows Service. 我的建议是这样做,并将其设置为作为Windows服务运行。

See this article: http://msdn.microsoft.com/en-us/library/ff649818.aspx 请参阅此文章: http//msdn.microsoft.com/en-us/library/ff649818.aspx

I am guessing the issue you are having is that you need to setup the SPN (Service Principal Name) for your WCF service (on the machine) and have it added to the service account under which the service is running. 我猜您遇到的问题是您需要为您的WCF服务(在计算机上)设置SPN(服务主体名称),并将其添加到运行该服务的服务帐户。

If you are running it under the default app pool user, then you need to have the SPN configured for the machine. 如果您在默认应用程序池用户下运行它,则需要为该计算机配置SPN。

I know it is troubling, and typically is the surprise waiting fro us devs once our service is ready to deploy to production or pre-production environments. 我知道这很令人不安,一旦我们的服务准备好部署到生产环境或预生产环境,通常会让我们感到惊讶。

The SPN is used by Kerberos during the authentication process. 在身份验证过程中,Kerberos会使用SPN。

Try using the IP of the machine to resolve your service instead of the hostname. 尝试使用计算机的IP来解析您的服务而不是主机名。 (This is not supposed to require an SPN), replace "test.mydomain.com" by the machine IP address: (这不应该要求SPN),用机器IP地址替换“test.mydomain.com”:

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

Take a look at these articles: - Kerberos for the Busy Admin 看看这些文章: - 忙碌管理员的Kerberos
- WCF on intranet with windows authentication - 具有Windows身份验证的Intranet上的WCF
- For the following post, try to read the one that is not accepted as an answer: What SPN do I need to set for a net.tcp service? - 对于以下帖子,尝试阅读一个不被接受的答案: 我需要为net.tcp服务设置什么SPN?

Did you tried to host service (for the testing purpose) in a Windows service on your local machine? 您是否尝试在本地计算机上的Windows服务中托管服务(用于测试目的)? This way you will at least know if the problem is on the service side or it's IIS/server configuration. 这样您至少可以知道问题出在服务端还是IIS /服务器配置上。

您在服务器上运行Net.TCP端口共享服务我猜...没有明确说明它。

I had a similar problem here today, while calling a net.tcp wcf service from inside an asp.net web api. 今天我遇到了类似的问题,同时从asp.net web api中调用net.tcp wcf服务。 I won't say that from all the other machines this service has worked for years, but the calls were made wcf self hosting, wcf iis asp.net compatibility hosting -> against the net.tcp service self hosted. 我不会说这个服务已经工作了多年的所有其他机器,但是调用是由wcf自托管,wcf iis asp.net兼容托管 - >反对net.tcp服务自托管。 When then I published my simple web api calling the same net.tcp service, everything went wrong, and all the connection were aborted without any reason, even the full wcf tracing both sides (service and client) did not helped, just telling the same "connection aborted". 然后我发布了我的简单web api调用相同的net.tcp服务,一切都出错,并且所有连接都没有任何理由中止,即使完整的wcf跟踪双方(服务和客户端)都没有帮助,只是告诉同样的“连接中止”。

I've already knew that net.tcp comes with the security over transport enabled, using windows authentication to sign and crypt the communication, so well, I just tried to turn off the security and everything start to work properly. 我已经知道net.tcp带有启用传输的安全性,使用Windows身份验证来签名和加密通信,所以,我只是试图关闭安全性,一切都开始正常工作。

Just give it a try turning off the security in this way both sides (client and service): 试试这两种方式(客户端和服务)关闭安全性:

<security mode="None"/>

full service binding: 全服务绑定:

<netTcpBinding>

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

        <security mode="None"/>

    </binding>

</netTcpBinding>

I hope this can help you too. 我希望这对你也有帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM