http://www.cnblogs.com/salonliudong/archive/2007/06/16/785604.html
一、Web Service簡介
1.1、Web Service基本概念
Web Service也叫XML Web Service WebService是一種可以接收從Internet或者Intranet上的其它系統中傳遞過來的請求,輕量級的獨立的通訊技術。是:通過SOAP在Web上提供的軟件服務,使用WSDL文件進行說明,并通過UDDI進行注冊。
XML:(Extensible Markup Language)擴展型可標記語言。面向短期的臨時數據處理、面向萬維網絡,是Soap的基礎。
Soap:(Simple Object Access Protocol)簡單對象存取協議。是XML Web Service 的通信協議。當用戶通過UDDI找到你的WSDL描述文檔后,他通過可以SOAP調用你建立的Web服務中的一個或多個操作。SOAP是XML文檔形式的調用方法的規范,它可以支持不同的底層接口,像HTTP(S)或者SMTP。
WSDL:(Web Services Description Language) WSDL 文件是一個 XML 文檔,用于說明一組 SOAP 消息以及如何交換這些消息。大多數情況下由軟件自動生成和使用。
UDDI (Universal Description, Discovery, and Integration) 是一種根據描述文檔來引導系統查找相應服務的機制。UDDI利用SOAP消息機制(標準的XML/HTTP)來發布,編輯,瀏覽以及查找注冊信息。它采用XML格式來封裝各種不同類型的數據,并且發送到注冊中心或者由注冊中心來返回需要的數據。
1.2、XML Web Service的特點
Web Service的主要目標是跨平臺的可互操作性。為了實現這一目標,Web Service 完全基于XML(可擴展標記語言)、XSD(XML Schema)等獨立于平臺、獨立于軟件供應商的標準,是創建可互操作的、分布式應用程序的新平臺。因此使用Web Service有許多優點:
1、跨防火墻的通信
如果應用程序有成千上萬的用戶,而且分布在世界各地,那么客戶端和服務器之間的通信將是一個棘手的問題。因為客戶端和服務器之間通常會有防火墻或者代理服務器。傳統的做法是,選擇用瀏覽器作為客戶端,寫下一大堆ASP頁面,把應用程序的中間層暴露給最終用戶。這樣做的結果是開發難度大,程序很難維護。 要是客戶端代碼不再如此依賴于HTML表單,客戶端的編程就簡單多了。如果中間層組件換成Web Service的話,就可以從用戶界面直接調用中間層組件,從而省掉建立ASP頁面的那一步。要調用Web Service,可以直接使用Microsoft SOAP Toolkit或.NET這樣的SOAP客戶端,也可以使用自己開發的SOAP客戶端,然后把它和應用程序連接起來。不僅縮短了開發周期,還減少了代碼復雜度,并能夠增強應用程序的可維護性。同時,應用程序也不再需要在每次調用中間層組件時,都跳轉到相應的“結果頁”。
2、應用程序集成
企業級的應用程序開發者都知道,企業里經常都要把用不同語言寫成的、在不同平臺上運行的各種程序集成起來,而這種集成將花費很大的開發力量。應用程序經常需要從運行的一臺主機上的程序中獲取數據;或者把數據發送到主機或其它平臺應用程序中去。即使在同一個平臺上,不同軟件廠商生產的各種軟件也常常需要集成起來。通過Web Service,應用程序可以用標準的方法把功能和數據“暴露”出來,供其它應用程序使用。
3、B2B的集成
B2B 指的是Business to Business,as in businesses doing business with other businesses,商家(泛指企業)對商家的電子商務,即企業與企業之間通過互聯網進行產品、服務及信息的交換。通俗的說法是指進行電子商務交易的供需雙方都是商家(或企業、公司),她們使用了Internet的技術或各種商務網絡平臺,完成商務交易的過程。
Web Service是B2B集成成功的關鍵。通過Web Service,公司可以只需把關鍵的商務應用“暴露”給指定的供應商和客戶,就可以了,Web Service運行在Internet上,在世界任何地方都可輕易實現,其運行成本就相對較低。Web Service只是B2B集成的一個關鍵部分,還需要許多其它的部分才能實現集成。 用Web Service來實現B2B集成的最大好處在于可以輕易實現互操作性。只要把商務邏輯“暴露”出來,成為Web Service,就可以讓任何指定的合作伙伴調用這些商務邏輯,而不管他們的系統在什么平臺上運行,使用什么開發語言。這樣就大大減少了花在B2B集成上的時間和成本。
4、軟件和數據重用
Web Service在允許重用代碼的同時,可以重用代碼背后的數據。使用Web Service,再也不必像以前那樣,要先從第三方購買、安裝軟件組件,再從應用程序中調用這些組件;只需要直接調用遠端的Web Service就可以了。另一種軟件重用的情況是,把好幾個應用程序的功能集成起來,通過Web Service “暴露”出來,就可以非常容易地把所有這些功能都集成到你的門戶站點中,為用戶提供一個統一的、友好的界面。 可以在應用程序中使用第三方的Web Service 提供的功能,也可以把自己的應用程序功能通過Web Service 提供給別人。兩種情況下,都可以重用代碼和代碼背后的數據。
從以上論述可以看出,Web Service 在通過Web進行互操作或遠程調用的時候是最有用的。不過,也有一些情況,Web Service根本不能帶來任何好處,Web Service有一下缺點:
1、 單機應用程序
目前,企業和個人還使用著很多桌面應用程序。其中一些只需要與本機上的其它程序通信。在這種情況下,最好就不要用Web Service,只要用本地的API就可以了。COM非常適合于在這種情況下工作,因為它既小又快。運行在同一臺服務器上的服務器軟件也是這樣。當然Web Service 也能用在這些場合,但那樣不僅消耗太大,而且不會帶來任何好處。
2、 局域網的一些應用程序
在許多應用中,所有的程序都是在Windows平臺下使用COM,都運行在同一個局域網上。在這些程序里,使用DCOM會比SOAP/HTTP有效得多。與此相類似,如果一個.NET程序要連接到局域網上的另一個.NET程序,應該使用.NET Remoting。其實在.NET Remoting中,也可以指定使用SOAP/HTTP來進行Web Service 調用。不過最好還是直接通過TCP進行RPC調用,那樣會有效得多。
1.3、XML Web Service的應用
1.最初的 XML Web Service 通常是可以方便地并入應用程序的信息來源,如股票價格、天氣預報、體育成績等等。
2.以 XML Web Service 方式提供現有應用程序,可以構建新的、更強大的應用程序,并利用 XML Web Service 作為構造塊。
例如,用戶可以開發一個采購應用程序,以自動獲取來自不同供應商的價格信息,從而使用戶可以選擇供應商,提交訂單,然后跟蹤貨物的運輸,直至收到貨物。而供應商的應用程序除了在Web上提供服務外,還可以使用XML Web Service檢查客戶的信用、收取貨款,并與貨運公司辦理貨運手續。
二、Web Service開發
.NET平臺內建了對Web Service的支持,包括Web Service的構建和使用。與其它開發平臺不同,使用.NET平臺,你不需要其他的工具或者SDK就可以完成Web Service的開發了。.NET Framework本身就全面支持Web Service,包括服務器端的請求處理器和對客戶端發送和接受SOAP消息的支持。下來我們就一步一步的用Microsoft Visual Studio .NET 2005(后面簡稱VS.Net 2005)創建和使用一個簡單的Web Service。
2.1、用創建一個最簡單的Web Service
首先,打開VS2005,打開“文件-新建-網站”,選擇“ASP.NET Web服務”。

查看Service.cs代碼,你會發現VS.Net 2005已經為Web Service文件建立了缺省的框架。原始代碼為:
1 using System;
2 using System.Web;
3 using System.Web.Services;
4 using System.Web.Services.Protocols
5 [WebService(Namespace = "http://tempuri.org/")]
6 [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
7 public class Service : System.Web.Services.WebService
8 {
9 public Service ()
10 //如果使用設計的組件,請取消注釋以下行
11 //InitializeComponent();
12 }
13 [WebMethod]
14 public string HelloWorld() {
15 return "Hello World";
16 }
17 }
默認工程里面已經有一個Hello World的方法了,直接運行看看效果,
點擊顯示頁面上圖中的“HelloWorld”超鏈接,跳轉到下一頁面

再點擊“調用”按鈕,就可以看到用XML格式返回的Web Service結果下圖。說明我們的Web Service環境沒有問題,而且還初步接觸了一下最簡單的Web Service。

2.2、創建一個帶有簡單功能的Web Service
上面我們宏觀的了解了webservice,其實它就是個對外的接口,里面有函數可供外部客戶調用(注意:里面同樣有客戶不可調用的函數).假若我們是服務端,我們寫好了個webservice,然后把它給了客戶(同時我們給了他們調用規則),客戶就可以在從服務端獲取信息時處于一個相對透明的狀態.即是客戶不了解(也不需要)其過程,他們只獲取數據.在代碼文件里,如果我們寫了一個函數后,希望此函數成為外部可調用的接口函數,我們必須在函數上面添上一行代碼[WebMethod],如果你的函數沒有這個申明,它將不能被用戶引用。WebMethod方法有幾種屬性需要說明:
1、WebMethod 的 BufferResponse 屬性 啟用對 XML Web services 方法響應的緩沖。當設置為 true(默認設置)時,ASP.NET 在將響應向下發送到客戶端之前對整個響應進行緩沖。
[WebMethod(BufferResponse=false)]
2、WebMethod 的 CacheDuration 屬性 啟用對 XML Web services 方法結果的緩存。ASP.NET 將緩存每個唯一參數集的結果。
[WebMethod(CacheDuration=60)]
3、WebMethod 的 Description 屬性 提供 XML Web services 方法的說明,該說明將顯示在服務幫助頁上。除非另外指定,默認值為空字符串。
[WebMethod(Description="我的方法")]
4、WebMethod 的 EnableSession 屬性 啟用 XML Web services 方法的會話狀態。一旦啟用,XML Web services 就可以從 HttpContext.Current.Session 中直接訪問會話狀態集合,或者,如果它是從 WebService 基類繼承的,則可以使用 WebService.Session 屬性來訪問會話狀態集合。除非另外指定,默認值為 false。
[WebMethod(EnableSession=true)]
5、WebMethod 的 MessageName 屬性) 使 XML Web services 能夠唯一確定使用別名的重載方法。除非另外指定,默認值是方法名稱。當指定 MessageName 時,結果 SOAP 消息將反映該名稱,而不是實際的方法名稱。
[WebMethod(MessageName="AddDoubles")]
6、WebMethod 的 TransactionOption 屬性 使 XML Web services 方法可以作為事務的根對象參與。雖然可以將 TransactionOption 屬性 設置為 TransactionOption 枚舉的任意值,但 XML Web services 方法僅有兩個可能的行為:它不參與事務或它創建一個新事務。
using System.EnterpriseServices;
[WebMethod(TransactionOption=TransactionOption.RequiresNew)]
下來我們開始編寫一個簡單的Web Service 的例子。
先把默認的HelloWorld方法注釋掉,簡單的寫了求加減乘除運算的四個方法;
1 using System;
2 using System.Web;
3 using System.Web.Services;
4 using System.Web.Services.Protocols;
5
6 [WebService(Namespace = "http://tempuri.org/")]
7 [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
8 public class Service : System.Web.Services.WebService
9 {
10 public Service () {
11 //如果使用設計的組件,請取消注釋以下行
12 //InitializeComponent();
13 }
14 //[WebMethod]
15 //public string HelloWorld() {
16 // return "Hello World";
17 //}
18 [WebMethod(Description="求和的方法")]
19 public double addition(double i,double j)
20 {
21 return i + j;
22 }
23 [WebMethod(Description="求差的方法")]
24 public double subtract(double i, double j)
25 {
26 return i - j;
27 }
28 [WebMethod(Description="求積的方法")]
29 public double multiplication(double i, double j)
30 {
31 return i * j;
32 }
33 [WebMethod(Description="求商的方法")]
34 public double division(double i, double j)
35 {
36 if (j != 0)
37 return i / j;
38 else
39 return 0;
40 }
41 }
42
運行可以看到我們自己寫的可以被調用的方法,如下圖:

同樣點擊addition方法,進入addition方法的調用頁。

在參數上面輸入參數i=3,j=3,如上圖,點擊調用,就可以看到用XML格式返回的Web Service結果(i與j相加的結果)下圖
到這里,我們會發現,其實webservice并不是那么的神秘,它也不過只是個接口,對我們而言,側重點就是是接口函數的編寫.
2.3、用ASP.NET調用Web Service
首先,打開VS2005,打開“文件-新建-網站”,選擇“ASP.NET網站”。
選好存儲位置,語言后點擊確定,進入默認頁面。然后先添加Web引用,把WebService引到當前的工程里面。方法是:在資源管理器中點擊右鍵,選擇添加Web 引用,調出對話框:

在URL中填入,前面寫好的WebService運行后瀏覽器上面顯示的地址,點擊“前往”按鈕,如上圖,就會顯示出所引用的WebService中可以調用的方法,然后點擊“添加引用”,就將webservice引用到了當前的工程里面 ,如下圖,解決方案中會出現引進來的WebService文件
我們在這就練習調用webservice的四個方法,做一個簡單的調用的例子,先在網站的前臺添加幾個控件,代碼如下:
1 <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
2
3 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
4 <html xmlns="http://www.w3.org/1999/xhtml" >
5 <head runat="server">
6 <title>Webservice調用實例</title>
7 </head>
8 <body>
9 <form id="form1" runat="server">
10 <div>
11 <asp:TextBox ID="Num1" runat="server"></asp:TextBox>
12 <select id="selectOper" runat = "server">
13 <option>+</option>
14 <option>-</option>
15 <option>*</option>
16 <option>/</option>
17 </select>
18 <asp:TextBox ID="Num2" runat="server"></asp:TextBox>
19 <span id = E runat = "server"></span>
20 <asp:TextBox ID="Result" runat="server"></asp:TextBox>
21 </div>
22 </form>
23 </body>
24 </html>
25
然后在后臺寫調用的代碼,調用之前和使用其它的對象一樣,要先實例化,實例化的方法是localhost.Service a = new localhost.Service();然后就可以通過a來訪問WebService里面提供的方法了。在這個例子里面,動態的創建了一個button控件來觸發WebService的調用,后臺代碼如下:
1 using System;
2 using System.Data;
3 using System.Configuration;
4 using System.Web;
5 using System.Web.Security;
6 using System.Web.UI;
7 using System.Web.UI.WebControls;
8 using System.Web.UI.WebControls.WebParts;
9 using System.Web.UI.HtmlControls;
10 public partial class _Default : System.Web.UI.Page
11 {
12 protected void Page_Load(object sender, EventArgs e)
13 {
14 //在頁面加載的時候動態創建一個按鈕,在它的事件里調用Webservice
15 Button btn = new Button();
16 btn.Width = 20;
17 btn.Text = " = ";
18 btn.Click +=new EventHandler(btn_Click);
19 E.Controls.Add(btn);
20 }
21 /// <summary>
22 /// 定義動態創建Button的Click事件,在這個事件中調用Webservice
23 /// </summary>
24 /// <param name="sender"></param>
25 /// <param name="e"></param>
26 void btn_Click(object sender, EventArgs e)
27 {
28 if (Num1.Text != "" && Num2.Text != "")
29 {
30 //實例化引用的webservice對象
31 localhost.Service WebserviceInstance = new localhost.Service();
32 int Oper = selectOper.SelectedIndex;
33 switch( Oper)
34 {
35 //通過實例化的webservice對象來調用Webservice暴露的方法
36 case 0:
37 Result.Text = WebserviceInstance.addition(double.Parse(Num1.Text), double.Parse(Num2.Text)).ToString();
38 break;
39 case 1:
40 Result.Text = WebserviceInstance.subtract(double.Parse(Num1.Text), double.Parse(Num2.Text)).ToString();
41 break;
42 case 2:
43 Result.Text = WebserviceInstance.multiplication(double.Parse(Num1.Text), double.Parse(Num2.Text)).ToString();
44 break;
45 case 3:
46 Result.Text = WebserviceInstance.division(double.Parse(Num1.Text), double.Parse(Num2.Text)).ToString();
47 break;
48 }
49 }
50 }
51 }
52
運行后可以看到效果,如下圖所示,在前面兩個Textbox里面輸入兩個操作數,在中間的下拉列表中選擇操作符,然后點擊“=”號,將計算的結果輸出到第三個Textbox里面。

而整個計算并不是在本地進行的,是在Web服務端進行計算的然后將結果通過XML返還給了調用方的,所以,在運行該程序的時候,WebService程序還必須啟動,否則會報無法連接遠程服務器的異常,如下圖:

到此一個一個簡單的WebService的開發和調用就已經完成了,在實際應用中可以根據自己的需要,寫一些功能強大的,復雜的WebService,不管多么復雜,整個流程都是這樣的。
I got a YES for the first submission.
I learned that devising and testing program on a paper is quite effective. It's easier to edit and modify. Once you've finished coding, it's harder to modify your program.
And devising at least several test cases before submitting your program. It's quite often that the Sample is somewhat misleading, there used to be long way between YES and merely making your program pass the Sample test.
Most importantly, I can feel some improvement on my coding skills no matter how easy the problem I'm trying to solve seems to be. Just write your code, once day you will feel the improvements.
UVA457是個水題,但是我還是碰到了一些小問題。
1.開了一個state[50][42]數組在main函數里面,結果提交之后發現runtime error,覺著是堆棧溢出了。突然想起來50*42>2000,這種數組一定是開在main外面的,不然必然堆棧溢出。
2.是讀題不仔細,當成了多重輸入,搞了一個while(scanf(...)),結果超時了。第一次在UVA OJ上面超時。
但是這篇文章重點不是講這個,而是講我在運行過程中經常遇到的core dumped現象。我在網上找到一點資料,貼在下面:
原帖:http://blogold.chinaunix.net/u3/98822/showart_2093542.html
什么是Core Dump?
Core的意思是內存, Dump的意思是扔出來, 堆出來.
開發和使用Unix程序時, 有時程序莫名其妙的down了, 卻沒有任何的提示(有時候會提示core dumped). 這時候可以查看一下有沒有形如core.進程號的文件生成, 這個文件便是操作系統把程序down掉時的內存內容扔出來生成的, 它可以做為調試程序的參考.
core dump又叫核心轉儲, 當程序運行過程中發生異常, 程序異常退出時, 由操作系統把程序當前的內存狀況存儲在一個core文件中, 叫core dump.
如何使用core文件?
gdb -c core文件路徑 [應用程序的路徑]
進去后輸入where回車, 就可以顯示程序在哪一行當掉的, 在哪個函數中.
為什么沒有core文件生成呢?
有時候程序down了, 但是core文件卻沒有生成. core文件的生成跟你當前系統的環境設置有關系, 可以用下面的語句設置一下, 然后再運行程序便成生成core文件.
ulimit -c unlimited
【沒有找到core文件,我們改改ulimit的設置,讓它產生。1024是隨便取的,要是core文件大于1024個塊,就產生不出來了。)
$ ulimit -c 1024 (轉者注: 使用-c unlimited不限制core文件大小】
core文件生成的位置一般于運行程序的路徑相同, 文件名一般為core.進程號
4. 用gdb查看core文件:
下面我們可以在發生運行時信號引起的錯誤時發生core dump了.
發生core dump之后, 用gdb進行查看core文件的內容, 以定位文件中引發core dump的行.
gdb [exec file] [core file]
如:
gdb ./test test.core
在進入gdb后, 用bt命令查看backtrace以檢查發生程序運行到哪里, 來定位core dump的文件->行.
===========================================================================
造成程序core dump的原因很多,這里根據以往的經驗總結一下:
1 內存訪問越界
a) 由于使用錯誤的下標,導致數組訪問越界
b) 搜索字符串時,依靠字符串結束符來判斷字符串是否結束,但是字符串沒有正常的使用結束符
c) 使用strcpy, strcat, sprintf, strcmp, strcasecmp等字符串操作函數,將目標字符串讀/寫爆。應該使用strncpy, strlcpy, strncat, strlcat, snprintf, strncmp, strncasecmp等函數防止讀寫越界。
2 多線程程序使用了線程不安全的函數。
應該使用下面這些可重入的函數,尤其注意紅色標示出來的函數,它們很容易被用錯:
asctime_r(3c) gethostbyname_r(3n) getservbyname_r(3n) ctermid_r(3s) gethostent_r(3n) getservbyport_r(3n) ctime_r(3c) getlogin_r(3c) getservent_r(3n) fgetgrent_r(3c) getnetbyaddr_r(3n) getspent_r(3c) fgetpwent_r(3c) getnetbyname_r(3n) getspnam_r(3c) fgetspent_r(3c) getnetent_r(3n) gmtime_r(3c) gamma_r(3m) getnetgrent_r(3n) lgamma_r(3m) getauclassent_r(3) getprotobyname_r(3n) localtime_r(3c) getauclassnam_r(3) etprotobynumber_r(3n) nis_sperror_r(3n) getauevent_r(3) getprotoent_r(3n) rand_r(3c) getauevnam_r(3) getpwent_r(3c) readdir_r(3c) getauevnum_r(3) getpwnam_r(3c) strtok_r(3c) getgrent_r(3c) getpwuid_r(3c) tmpnam_r(3s) getgrgid_r(3c) getrpcbyname_r(3n) ttyname_r(3c) getgrnam_r(3c) getrpcbynumber_r(3n) gethostbyaddr_r(3n) getrpcent_r(3n)
3 多線程讀寫的數據未加鎖保護。
對于會被多個線程同時訪問的全局數據,應該注意加鎖保護,否則很容易造成core dump
4 非法指針
a) 使用空指針
b) 隨意使用指針轉換。一個指向一段內存的指針,除非確定這段內存原先就分配為某種結構或類型,或者這種結構或類型的數組,否則不要將它轉換為這種結構或類型的指針,而應該將這段內存拷貝到一個這種結構或類型中,再訪問這個結構或類型。這是因為如果這段內存的開始地址不是按照這種結構或類型對齊的,那么訪問它時就很容易因為bus error而core dump.
5 堆棧溢出
不要使用大的局部變量(因為局部變量都分配在棧上),這樣容易造成堆棧溢出,破壞系統的棧和堆結構,導致出現莫名其妙的錯誤。
-------
我自己程序core dumped就是因為第5個原因,堆棧溢出。我的局部數組開的過大,而局部變量分配在棧上,導致堆棧溢出。