第二篇:聊聊binding
上一篇构建的WCF程序,binding指定的是basicHttpBinding,这是最基础的通讯方式,基于http,不加密,抓一下包的话,应该是这样的:
- 发送包:
- POST /wcf HTTP/1.1
- Content-Type: text/xml; charset=utf-8
- SOAPAction: "WCF.Demo/IData/SayHello"
- Host: 127.0.0.1:8080
- Content-Length: 156
- Expect: 100-continue
- Connection: Keep-Alive
- <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><SayHello xmlns="WCF.Demo"><userName>WCF</userName></SayHello></s:Body></s:Envelope>
- -------------------------
- 应答包:
- HTTP/1.1 100 Continue
- HTTP/1.1 200 OK
- Content-Length: 191
- Content-Type: text/xml; charset=utf-8
- Server: Microsoft-HTTPAPI/2.0
- Date: Mon, 05 Mar 2012 08:45:31 GMT
- <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><SayHelloResponse xmlns="WCF.Demo"><SayHelloResult>Hello WCF.</SayHelloResult></SayHelloResponse></s:Body></s:Envelope>
就是SOAP,和WebService是一样的。basicHttpBinding的优势在于通用,又基于http,所以在跨语言的开发中或者是穿透复杂网络环境时占优势,但是效率比较低,因为SOAP的序列化和反序列化比较耗时,传输的数据量也比较大,而且是明文,安全性差。
WCF的binding有很多种,包括:
basicHttpBinding(常用) | 符合WSBasicProfile 1.1标准,以提供最大的互操作性 |
wsHttpBinding(常用) | 符合WS-*协议的HTTP通讯,加密 |
wsDualHttpBinding | 双工http通信,初始信息的接收者不会直接响应发送者,而是可以在一定时间之内传送任意次的响应 |
wsFederationBinding | http通信,对服务资源的访问可以根据一个显式确定的凭据提供程序发出的凭据加以控制 |
netTcpBinding(常用) | 提供网络里WCF软件实体之间的安全可靠高性能的通信 |
netNamedPipeBinding | 同一台机器上的WCF软件实体之间的安全可靠高性能的通信 |
netMsmqBinding | WCF软件实体与其它软件实体间通过MSMQ通信 |
msmqIntegrationBinding | 软件实体与其它软件实体间通过MSMQ通信 |
netPeerTcpBinding | WCF软件实体间通过Windows对等网络技术通信 |
内容很多,我们挑wsHttpBinding和netTcpBinding继续研究一下,这两个最有代表性。在上一篇demo的基础上修改一下。
1、服务端
服务端的功能逻辑没有任何变化,只是调整绑定方式,所以只调整App.config:
- <?xml version="1.0" encoding="utf-8" ?>
- <configuration>
- <system.serviceModel>
- <services>
- <service name="Server.DataService">
- <host>
- <baseAddresses>
- <add baseAddress="http://localhost:8080/wcf" />
- <!-- 此处增加了个baseAddress,注意标头指定的是net.tcp,另外端口不能被占用 -->
- <add baseAddress="net.tcp://localhost:8081/wcf" />
- </baseAddresses>
- </host>
- <!-- 此处调整了绑定使用wsHttpBinding方式 -->
- <endpoint address="" binding="wsHttpBinding" contract="Server.IData" />
- <!-- 此处增加了一个endpoint,使用netTcpBinding方式,服务契约同样是IData -->
- <endpoint address="" binding="netTcpBinding" contract="Server.IData" />
- </service>
- </services>
- </system.serviceModel>
- </configuration>
与之前相比,增加了一个baseAddress和一个endpoint,另外调整了之前endpoint的绑定方式。现在针对同一个服务契约,有两个endpoint了,但是它们不会冲突,因为两者的网络协议不同,所以wsHttpBinding的会使用http://localhost:8080/wcf的地址,而netTcpBinding的会使用net.tcp://localhost:8081/wcf的地址。
如果同时定义了basicHttpBinding和wsHttpBinding呢?那么它们的address一定不能相同,因为baseAddress已经相同了,adress还一样,就无法访问了。
编译运行一下,然后命令行“netstat -ano”看一下,应该能看到8080和8081都开始监听了。
- TCP 0.0.0.0:8080 0.0.0.0:0 LISTENING 4
- TCP 0.0.0.0:8081 0.0.0.0:0 LISTENING 692
- TCP [::]:8080 [::]:0 LISTENING 4
- TCP [::]:8081 [::]:0 LISTENING 692
TCP 8081端口的PID显示是我们的服务程序在对外监听。
2、客户端
由于服务端修改了绑定方式,客户端必须要与之匹配,先修改App.config文件:
- <?xml version="1.0" encoding="utf-8" ?>
- <configuration>
- <system.serviceModel>
- <client>
- <!-- 此处调整了binding为wsHttpBinding -->
- <endpoint name="httpDataService" address="http://localhost:8080/wcf" binding="wsHttpBinding" contract="Server.IData" />
- <!-- 此处新增了一个endpoint,指定使用netTcpBinding方式 -->
- <endpoint name="tcpDataService" address="net.tcp://localhost:8081/wcf" binding="netTcpBinding" contract="Server.IData" />
- </client>
- </system.serviceModel>
- </configuration>
需要指出的是,服务端开放了2种访问方式,客户端不一定也要写2个endpoint,这里是为了测试两种绑定。
调用代码也要做个小修改:
- using System;
- using System.ServiceModel;
- using System.ServiceModel.Channels;
- namespace Client
- {
- class Program
- {
- static void Main(string[] args)
- {
- //定义一个http方式的代理,配置使用httpDataService中的定义
- var httpProxy = new ChannelFactory<Server.IData>("httpDataService").CreateChannel();
- Console.WriteLine(httpProxy.SayHello("WCF"));
- ((IChannel)httpProxy).Close();
- //定义一个tcp方式的代理,配置使用tcpDataService中的定义
- var tcpProxy = new ChannelFactory<Server.IData>("tcpDataService").CreateChannel();
- Console.WriteLine(tcpProxy.SayHello("WCF"));
- ((IChannel)tcpProxy).Close();
- }
- }
- }
编译运行一下,应该能够输出两行 Hello WCF.。
抓包看看:
wsHttpBinding方式的客户端与服务端总共交换了60多个数据包,这是因为双方要先握手交换密钥,另外由于数据加了密,长度也变大了。这里只截第一次交互的数据看看:
- 发送包:
- POST /wcf HTTP/1.1
- Content-Type: application/soap+xml; charset=utf-8
- Host: 127.0.0.1:8080
- Content-Length: 1106
- Expect: 100-continue
- Connection: Keep-Alive
- <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing"><s:Header><a:Action s:mustUnderstand="1">http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue</a:Action><a:MessageID>urn:uuid:144b8aeb-6ac1-46f5-8361-957425b827c8</a:MessageID><a:ReplyTo><a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address></a:ReplyTo><a:To s:mustUnderstand="1">http://192.168.90.81:8080/wcf</a:To></s:Header><s:Body><t:RequestSecurityToken Context="uuid-156d27d6-3db7-43ac-b488-12f9ae123861-1" xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust"><t:TokenType>http://schemas.xmlsoap.org/ws/2005/02/sc/sct</t:TokenType><t:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</t:RequestType><t:KeySize>256</t:KeySize><t:BinaryExchange ValueType="http://schemas.xmlsoap.org/ws/2005/02/trust/spnego" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">TlRMTVNTUAABAAAAt7IY4gkACQAxAAAACQAJACgAAAAGAbAdAAAAD1RJQU5ZVS1QQ1dPUktHUk9VUA==</t:BinaryExchange></t:RequestSecurityToken></s:Body></s:Envelope>
- ---------------------
- 应答包:
- HTTP/1.1 100 Continue
- HTTP/1.1 200 OK
- Content-Length: 1044
- Content-Type: application/soap+xml; charset=utf-8
- Server: Microsoft-HTTPAPI/2.0
- Date: Tue, 06 Mar 2012 01:46:24 GMT
- <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing"><s:Header><a:Action s:mustUnderstand="1">http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/Issue</a:Action><a:RelatesTo>urn:uuid:144b8aeb-6ac1-46f5-8361-957425b827c8</a:RelatesTo></s:Header><s:Body><t:RequestSecurityTokenResponse Context="uuid-156d27d6-3db7-43ac-b488-12f9ae123861-1" xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><t:BinaryExchange ValueType="http://schemas.xmlsoap.org/ws/2005/02/trust/spnego" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">TlRMTVNTUAACAAAAEgASADgAAAA1wprik+hmjwEji3X4ciEAAAAAAGgAaABKAAAABgGwHQAAAA9UAEkAQQBOAFkAVQAtAFAAQwACABIAVABJAEEATgBZAFUALQBQAEMAAQASAFQASQBBAE4AWQBVAC0AUABDAAQAEgBUAGkAYQBuAFkAdQAtAFAAQwADABIAVABpAGEAbgBZAHUALQBQAEMABwAIAPm5CvA6+8wBAAAAAA==</t:BinaryExchange></t:RequestSecurityTokenResponse></s:Body></s:Envelope>
应该是双方交换了一个256位的密钥,反正所有的数据交互都不再是明文的了。
再来看netTcpBinding的这次,还是只截一小段吧:
- 发送包:
- 00000000 00 01 00 01 02 02 20 6E 65 74 2E 74 63 70 3A 2F ...... n et.tcp:/
- 00000010 2F 31 39 32 2E 31 36 38 2E 39 30 2E 38 31 3A 38 /192.168 .90.81:8
- 00000020 30 38 31 2F 77 63 66 03 08 09 15 61 70 70 6C 69 081/wcf. ...appli
- 00000030 63 61 74 69 6F 6E 2F 6E 65 67 6F 74 69 61 74 65 cation/n egotiate
- 00000040 16 01 00 00 3A 4E 54 4C 4D 53 53 50 00 01 00 00 ....:NTL MSSP....
- 00000050 00 B7 B2 18 E2 09 00 09 00 31 00 00 00 09 00 09 ........ .1.....
- ----------
- 应答包:
- 00000000 0A 16 01 00 00 B2 4E 54 4C 4D 53 53 50 00 02 00 ......NT LMSSP...
- 00000010 00 00 12 00 12 00 38 00 00 00 35 C2 9A E2 3A D5 ......8. ..5...:.
- 00000020 19 64 33 D4 B9 7C F8 72 21 00 00 00 00 00 68 00 .d3..|.r !.....h.
- 00000030 68 00 4A 00 00 00 06 01 B0 1D 00 00 00 0F 54 00 h.J..... ......T.
- 00000040 49 00 41 00 4E 00 59 00 55 00 2D 00 50 00 43 00 I.A.N.Y. U.-.P.C.
- 00000050 02 00 12 00 54 00 49 00 41 00 4E 00 59 00 55 00 ....T.I. A.N.Y.U.
从效率上讲,tcp方式要比http方式高得多,同时http方式,basicHttpBinding又要比wsHttpBinding高得多,在实际使用中,大家要看需求来决定使用哪种方式。
OK,下一篇我们看看能不能不用写复杂的配置就发布WCF服务,也以此来加深一下对Host、Contract、Binding、BaseAddress的理解。
本文转自 BoyTNT 51CTO博客,原文链接:http://blog.51cto.com/boytnt/796993,如需转载请自行联系原作者