傳統上,我們把計算機后台程序(Daemon)提供的功能,稱為"服務"(service)。比如,讓一個殺毒軟件在后台運行,它會自動監控系統,那么這種自動監控就是一個"服務"。
通俗地說,"服務"就是計算機可以提供的某一種功能。
根據來源的不同,"服務"又可以分成兩種:一種是"本地服務"(使用同一台機器提供的服務,不需要網絡),另一種是"網絡服務"(使用另一台計算機提供的服務,必須通過
網絡才能完成)。"網絡服務"(Web Service)的本質,就是通過網絡調用其他網站的資源。舉例來說,去年公開課的時候我在ArcGIS Engine中調用過一個天氣預報的信息,並將信息和具體的位置關聯起來。所以,Web service讓你的網站可以使用其他網站的資源,比如在網頁上顯示天氣、地圖、twitter上的最新動態等等。
綜上:WebService是兩個計算機之間通訊(交談)的技術。並且現在炒的很火的SOA、雲計算在技術層面上都是WebService。
除了WebService 通訊外,系統間通訊有很多種技術,如像qq的這種Socket通訊在銀行系統中廣泛應用,.Net Remoting、DCom等通訊方式也應用很 多,
但是這些方式有如下缺點:
• 通訊數據格式不統一,同樣一個"你好"這樣的字符串在不同的協議中有不同的表示方法,異構系統集成很麻煩。一個系統一個模樣。
• 采用Socket、 .Net Remoting、DCom需要打開很多端口,而企業網絡安全的一個基本原則就是“盡可能少的打開端口”,很多企業網絡甚至嚴格規定“只能打開80端口”,
因此需要一種“跨防火牆”的技術(跨防火牆就是走80端口進行通訊)
• 這些通訊方式的協議是不開放的,要想知道服務提供了哪些方法、如何調用,必須能夠自描述
WSDL(Web Service Description Language)
你會怎樣向別人介紹你的Web service有什么功能,以及每個函數調用時的參數呢?你可能會自己寫一套文檔,你甚至可能會口頭上告訴需要使用你的Web service的人。
這些非正式的方法至少都有一個嚴重的問題:當程序員坐到電腦前,想要使用你的Web service的時候,他們的工具(如Visual Studio)無法給他們提供任何幫助,因為這些工具根本就不了解你的Web service。解決方法是:用機器能閱讀的方式提供一個正式的描述文檔。Web service描述語言(WSDL)就是這樣一個基於XML的語言,用於描述Web service及其函數、參數和返回值。因為是基於XML的,所以WSDL既是機器可閱讀的,又是人可閱讀的,這將是一個很大的好處。一些最新的開發工具既能根據你的Web service生成WSDL文檔,又能導入WSDL文檔,生成調用相應Web service的代碼
Web服務器描述語言是用XML文檔來描述Web服務的標准,是Web服務的接口定義語言,由Ariba、Intel、IBM、MS等共同提出,通過WSDL,可描述Web服務的三個基本屬性:
·服務做些什么——服務所提供的操作(方法)
·如何訪問服務——和服務交互的數據格式以及必要協議
·服務位於何處——協議相關的地址,如URL
XML和XSD
可擴展的標記語言(XML)是Web service平台中表示數據的基本格式。除了易於建立和易於分析外,XML主要的優點在於它既是平台無關的,又是廠商無關的。無關性是比技術優越性更重要的:軟件廠商是不會選擇一個由競爭對手所發明的技術的。
XML解決了數據表示的問題,但它沒有定義一套標准的數據類型,更沒有說怎么去擴展這套數據類型。例如,整形數到底代表什么?16位,32位,還是64位?這些細節對實現互操作性都是很重要的。W3C制定的XML Schema(XSD)就是專門解決這個問題的一套標准。它定義了一套標准的數據類型,並給出了一種語言來擴展這套數據類型。Web service平台就是用XSD來作為其數據類型系統的。當你用某種語言(如VB.NET或C#)來構造一個Web service時,為了符合Web service標准,所有你使用的數據類型都必須被轉換為XSD類型。你用的工具可能已經自動幫你完成了這個轉換,但你很可能會根據你的需要修改一下轉換過程。在第二章中,我們將深入XSD,學習怎樣轉換自定義的數據類型(例如類)到XSD的類型。
SOAP
Web service建好以后,你或者其他人就會去調用它。簡單對象訪問協議(SOAP)提供了標准的RPC方法來調用Web service。實際上,SOAP在這里有點用詞不當:它意味着下面的Web service是以對象的方式表示的,但事實並不一定如此:你完全可以把你的Web service寫成一系列的C函數,並仍然使用SOAP進行調用。SOAP規范定義了SOAP消息的格式,以及怎樣通過HTTP協議來使用SOAP。SOAP也是基於XML和XSD的,XML是SOAP的數據編碼方式。第三章我們會討論SOAP,並結識SOAP消息的各種元素。
綜上我們還可以得出以下結論:
請求、返回的XML數據格式(有哪些節點、節點的名字等等)WebService 用SOAP協議進行規定,方法描述信息XML用WSDL協議規定。WebService技術是與語言、平台無關,因此.net可以訪問java編寫的WebService、java也可以訪問.net編寫的webservice,php、python等各種語言也幾乎都支持webservice,因此可以說webservice可以實現跨語言方法調用。
但是如果自己構建請求、返回xml,解析xml請求,自己負責方法描述信息更新是很麻煩的,.net就提供了簡化開發WebService。
WebService的創建和使用
WebService的使用過程包括服務器端代碼的編寫和客戶端代碼的調用,服務器端的代碼比較容易,只是在使用的時候需要添加一些[WebService]和[WebMethod]這樣的標記
1、 服務器端(ServerWeb):就想寫普通方法一樣,不需要處理請求、響應。服務器端新建“Web服務”(asmx),在遠端可以調用的方法上標注[WebMethod]。
using System; using System.Linq; using System.Web; using System.Web.Services; using System.Web.Services.Protocols; using System.Xml.Linq; [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] // 若要允許使用 ASP.NET AJAX 從腳本中調用此 Web 服務,請取消對下行的注釋。 // [System.Web.Script.Services.ScriptService] public class Service : System.Web.Services.WebService { public Service () { //如果使用設計的組件,請取消注釋以下行 //InitializeComponent(); } //[WebMethod] //public string HelloWorld() //{ // return "Hello World"; //} [WebMethod(Description = "求和的方法")] public double addition(double i, double j) { return i + j; } [WebMethod(Description = "求差的方法")] public double subtract(double i, double j) { return i - j; } [WebMethod(Description = "求積的方法")] public double multiplication(double i, double j) { return i * j; } [WebMethod(Description = "求商的方法")] public double division(double i, double j) { if (j != 0) return i / j; else return 0; } }
2、客戶端添加對asmx的“服務器引用”,然后就可以調用***SoapClient類中的方法。就“好像”直接調用了服務端的方法(因為VS2010中有兩種添加服務的方法,一種是早期的針對net2.0的,如果是2.0的話,會生成一個跟服務端同類名的類)。

添加服務引用的時候工具讀取asmx的WSDL自動生成了ServiceReference1中的類,這些類幫我們來拼Http請求,並且把Http返回值拆成函數的返回。
客戶端“添加服務引用”,填寫asmx的地址。然后就可以調用Service References下自動生成的***SoapClient類了。
用WebService的時候如果服務端的接口定義發生變化,則需要重新添加對服務端的引用,因為Service References中的類是工具讀取WSDL定義自動生成的。在服務引用上點擊右鍵,選擇“更新服務引用”。如果只是修改了WebService內部實現,而接口沒變,則不需要“更新服務引用”,因為WSDL沒變,Soap沒變。
static void Main(string[] args) { ServiceTest.ServiceSoapClient stsoap = new ServiceTest.ServiceSoapClient(); double c= stsoap.addition(1, 2); Console.WriteLine(c.ToString()); // vs 2010中兩種方式 ServiceTest.Service st = new ServiceTest.Service(); double a = st.addition(1, 2); Console.WriteLine(a.ToString()); Console.ReadKey(); }
.Net remoting
Net remoting 是簡化網絡通訊的技術,底層仍然是TCP等東西。
remoting要添加對System.Runtime.Remoting的引用
編寫服務接口類庫項目,正常寫法!WebService中WSDL相當於對服務端方法的描述;.net Remoting中走的是二進制數據,因此必須一個描述服務端方法的接口類庫。這個類庫里面往往是一個接口,定義了服務器端實現方法的方法名,客戶端和服務器端都需要引進用這個接口。
服務端實現服務接口,繼承自MarshalByRefObject,然后運行備注中的代碼注冊服務。
客戶端代碼在備注中
Remoting和WebService的區別:Remoting效率高,走的是普通TCP, WebService則是Http協議,需要IIS、ASP.Net、XML解析等,效率低。Remoting適合於內網通訊, WebService適合於外網通訊。
除非項目要求,否則以后盡量用WCF。.Net Remoting是微軟私有協議,因此如果要跨平台調用還是普通Socket或者WebService。
用法說明:
1、新建接口項目,定義服務接口。
注意:remoting要添加對System.Runtime.Remoting的引用
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace NETRemotiongInterface { public interface IRemotingTest { double add(double a,double b); } }
2、新建服務器端項目(控制台的,或者WinForm,或者Windows服務等)
定義實現服務接口的類,還要繼承繼承自MarshalByRefObject類
using System; using System.Collections.Generic; using System.Linq; using System.Text; using NETRemotiongInterface; namespace RemotingServer { class TestServiceImp : MarshalByRefObject,IRemotingTest
{ #region IRemotingTest 成員 public double add(double a, double b) { return a + b; } #endregion } }
3,服務器啟動時調用
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.Remoting.Channels.Tcp; using System.Runtime.Remoting; using System.Runtime.Remoting.Channels; namespace RemotingServer { class Program { static void Main(string[] args) { TcpChannel tcpChannel = new TcpChannel(9999); ChannelServices.RegisterChannel(tcpChannel); //注冊服務:第一個參數為服務的實現類,第二個參數為服務的名字。 RemotingConfiguration.RegisterWellKnownServiceType(typeof(TestServiceImp), "test", WellKnownObjectMode.Singleton); //注冊服務。如果控制台程序,控制不要讓程序退出, //主要目的是不要讓服務器退出 while (true) { string s = Console.ReadLine(); if (s == "quit") { return; } } } } }
,4、客戶端:新建客戶端項目,引用服務接口
namespace RemotingClient { class Program { static void Main(string[] args) { TcpChannel tcpChannel = new TcpChannel(); ChannelServices.RegisterChannel(tcpChannel, false); IRemotingTest test = (IRemotingTest)Activator.GetObject(typeof(IRemotingTest), "tcp://127.0.0.1:9999/test");//第一個參數為服務實現的接口,第二個參數為服務的地址:最后一部分是服務在服務器端RegisterWellKnownServiceType時第二個參數的名字然后就可以調用服務端方法了。 double a = test.add(1, 2); Console.WriteLine(a.ToString()); Console.ReadKey(); } } }
從WebService和NetRemoting來看客戶端都要知道服務器端暴露的功能,這個是必須的,要不然客戶端怎么調用,WS是通過一個地址,而NetRemoting是通過一個接口類庫,當然這也只是表面現象。
WCF
WCF(Windows Communication foundation)是微軟的統一網絡通訊開發的技術,無論底層用.Net Remoting還是WebService還是Restful還是MSMQ等,只要修改配置文件即可。所以WCF並不是新技術。
WCF和.Net Remoting、WebService等技術的關系就像ADO.Net和SQLServer、Oracle驅動的關系一樣。通過VS的“WCF服務配置編輯器”簡化配置,修改不同的協議。
一開始內網運行就行,后來想運行到公網,那么如果一開始用.net remoting寫后來改成WebService還是有工作量的,因為寫法不一樣,但是用WCF就不一樣了。
新建“WCF服務庫”,WCF服務庫可以Host在IIS上、單獨的WinForm程序等。
WCF、.Net Remoting和WebService的關系: .Net Remoting是普通的TCP通訊,適合於局域網,效率高; WebService是基於Http協議,適合於廣域網,效率低;WCF是對.Net Remoting、 WebService等的簡化、統一,可以通過配置來切換不同的底層實現,代碼幾乎不用動。
關於WCF的例子,我也懶得寫了,給出一篇博文,大家可以自行研究:http://www.cnblogs.com/oec2003/archive/2010/07/15/1778013.html
Socket的例子我們可能見得比較多,這里就不羅嗦了,啰嗦了,直接上代碼:
服務器端
using System; using System.Net; using System.Net.Sockets; using System.Text; public class SynchronousSocketClient { public static void StartClient() { // Data buffer for incoming data. byte[] bytes = new byte[1024]; // Connect to a remote device. try { // Establish the remote endpoint for the socket. // This example uses port 11000 on the local computer. IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName()) IPAddress ipAddress = ipHostInfo.AddressList[0]; IPEndPoint remoteEP = new IPEndPoint(ipAddress,11000); // Create a TCP/IP socket. Socket sender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp ); // Connect the socket to the remote endpoint. Catch any errors. try { sender.Connect(remoteEP); Console.WriteLine("Socket connected to {0}", sender.RemoteEndPoint.ToString()); // Encode the data string into a byte array. byte[] msg = Encoding.ASCII.GetBytes("This is a test<EOF>"); // Send the data through the socket. int bytesSent = sender.Send(msg); // Receive the response from the remote device. int bytesRec = sender.Receive(bytes); Console.WriteLine("Echoed test = {0}", Encoding.ASCII.GetString(bytes,0,bytesRec)); // Release the socket. sender.Shutdown(SocketShutdown.Both); sender.Close(); } catch (ArgumentNullException ane) { Console.WriteLine("ArgumentNullException : {0}",ane.ToString()); } catch (SocketException se) { Console.WriteLine("SocketException : {0}",se.ToString()); } catch (Exception e) { Console.WriteLine("Unexpected exception : {0}", e.ToString()); } } catch (Exception e) { Console.WriteLine( e.ToString()); } } public static int Main(String[] args) { StartClient(); return 0; } }
客戶端
using System; using System.Net; using System.Net.Sockets; using System.Text; public class SynchronousSocketListener { // Incoming data from the client. public static string data = null; public static void StartListening() { // Data buffer for incoming data. byte[] bytes = new Byte[1024]; // Establish the local endpoint for the socket. // Dns.GetHostName returns the name of the // host running the application. IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName()); IPAddress ipAddress = ipHostInfo.AddressList[0]; IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000); // Create a TCP/IP socket. Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp ); // Bind the socket to the local endpoint and // listen for incoming connections. try { listener.Bind(localEndPoint); listener.Listen(10); // Start listening for connections. while (true) { Console.WriteLine("Waiting for a connection"); // Program is suspended while waiting for an incoming connection. Socket handler = listener.Accept(); data = null; // An incoming connection needs to be processed. while (true) { bytes = new byte[1024]; int bytesRec = handler.Receive(bytes); data += Encoding.ASCII.GetString(bytes,0,bytesRec); if (data.IndexOf("<EOF>") > -1) { break; } } // Show the data on the console. Console.WriteLine( "Text received : {0}", data); // Echo the data back to the client. byte[] msg = Encoding.ASCII.GetBytes(data); handler.Send(msg); handler.Shutdown(SocketShutdown.Both); handler.Close(); } } catch (Exception e) { Console.WriteLine(e.ToString()); } Console.WriteLine("\nPress ENTER to continue"); Console.Read(); } public static int Main(String[] args) { StartListening(); return 0; } }
來點這四個的總結的話。
1:socket VS remoting
使用socket無疑是效率最高的。但是,在復雜的接口環境下,socket的開發效率也是最低的。故在兼顧開發效率的情況下,可以使用remoting來代替socket開發。並且:
1、Tcp通道的Remoting速度非常快。
你可以通過端口查看工具,發現remoting比直接socket傳輸的內容,應該是屬於同一個數量級的。我的另一個擔心是,大客戶端數量的情況下,remoting傳輸效率會不會很低,結果經過現場測試,同時對300個客戶端進行數據通信,不存在信息丟失情況。
2、雖然是遠程的,但是非常接近於本地調用對象。
也就是完全符合面向對象思想。
3、可以做到保持對象的狀態
直接使用socket傳輸機制,我們必須花大量的精力來處理異常、斷網、死機等現象,使用remoting,這些工作會大大簡化。
2:remoting vs webservice
1、webservice在framework2.0狀態下只能寄宿於IIS等應用服務器中。微軟直到3.0才提供了servicehost來寄宿 webservice,這就極大地限制了webservice在使用中的靈活性。在framework2.0環境下,如果你有一個應用要脫離IIS而存 在,就不得不拋棄webservice。(除非你想代碼實現一個WEB應用服務器)
2、remoting可寄宿在你自己的代碼中,也可寄宿在windows服務及IIS中。最大程度的提供了開發和部署的靈活性。
3、remoting在使用http通道的時候,也如webservice一樣支持穿透路由。
4、remoting與websercie相比,提供雙向通信。哪怕是將remoting寄宿在IIS中,也支持。
5、webservice客戶端自動生成的代理類比較復雜。而remoting一般來說,都是手動編寫客戶端代碼。
6、當然,webservice最主要優勢是,它是一個行業標准,而remoting只是微軟自己內部的標准,如果你的應用要脫離微軟的平台,就只能使用webservice了。
7,NetRemoting的優點是用戶既可以使用TCP信道方式進行二進制流方式通信,也可以使用HTTP信道進行SOAP格式的性通信,而WebService只能使用HTTP通道
8, NetRemotiong效率相對WebService要高不少;
9, Netremoting可以用於有狀態的情況,而WebService只能使用無狀態的情況。
3:remoting vs wcf
與wcf的比較,更多的是從平台的普及度上來說。在當前環境下,2.0的普及度還是最高的。如果哪一天3.0甚至4.0普及了,當然WCF是最好的。
參考:http://evencode.iteye.com/blog/1453046
http://www.cnblogs.com/oec2003/archive/2010/07/15/1778013.html
http://blog.csdn.net/zhoufoxcn/article/details/1649776
http://blog.csdn.net/huangxinfeng/article/details/4967629
