基于webservice協義,實作一個簡單的天氣預報
這些時間在玩黑莓,黑莓上有一款天氣預報的小軟體。個人出于好奇,想要研究一下該功能的實作過程。
網絡方面的程式一直很少接觸,算是一個盲點。是以剛開始, 理所當然的認為該功能的實作過程與ntp協定相似,都是用戶端,建立socket,與伺服器建立連接配接, 用戶端
發送帶有地點資訊的資料到伺服器,伺服器傳回包括該城市天氣資訊的資料到用戶端, 客戶解析資料,得到天氣資訊。
真正開始着手查詢相關的資料時,才知道網絡對些查詢服務協定已有明确的名字名義--webservice,以前似乎好像有聽過此概念。啥叫 webservice,字面上可以了解為網絡服務。
一個很簡單的例子來說明一下,什麼是webservice。計算1+1等于幾?用戶端與webservice伺服器建立連接配接, 告訴伺服器端我想要得到1+1 的結果, 伺服器進行運算,傳回計算結果給用戶端。
這不就是目前很火,引無數it巨頭竟腰的雲計算嗎?目前,在網絡上這樣的伺服器很多,有查詢股票資訊的, 有查詢天氣的,五花八門。
寫到webservice ,不得不提到gsoap。gsoap 更像是一個代碼生成器的工具,我們完全可以不利用gsoap,按照webservice的協義,個人編寫全部的代碼。有了gsoap 工具一切都好辦,
gsoap用戶端和伺服器的開發工作大為簡化。下面重點寫寫如何用gsoap 完成一個天氣預報用戶端的開發全過程。
1 下載下傳gsoap,并解壓到linux目錄下(/home/code/ ),下載下傳位址為http://sourceforge.net/projects/gsoap2/files/
#cd /home/code
#unzip gsoap_2.8.0.zip
2 解壓後,生成gsoap-2.8。一般情況下, 從網絡上下載下傳開發包,在本地怎麼都得先./configure 再 make一下,但是gsoap更像是一個工具包,解壓後,可以直接使用包裡面的工具,也就是soapcpp2和wsdl2h這兩個工具,
不同的平台對應的工具是不一樣,目前gsoap支援的平台有linux386,macosx ,win32,我所使用主機環境為fedora-9,是以應使用linux386下的工具。
#cd /home/code/gsoap-2.8/gsoap/bin/linux386
3 建立一個新的目錄,命名為weather
#mkdir weather
4 利用gsoap 工具生成webserice 協義代碼,wsdl2h從伺服器下載下傳頭檔案,soapcpp2相當于代碼生成品,根據頭檔案生成相應的.c檔案和.nsmap檔案。
#../wsdl2h -c -o weather.h http://www.ayandy.com/Service.asmx?WSDL
注 -c 生成.c檔案,相對于C++,個人還是一直偏好于C語言。
#../soapcpp2 -x -C -c weather.h
-x 不生成xml檔案
-C 隻生成用戶端相關代碼
5 拷貝/home/code/gsoap-2.8/gsoap目錄下的stdsoap2.h stdsoap2.c 兩個檔案到 weather目錄下。
#cp /home/code/gsoap-2.8/gsoap/stdsoap2.h ./
#cp /home/code/gsoap-2.8/gsoap/stdsoap2.c ./
6 編寫用戶端程式,也就是調用剛剛生成代碼中接口函數。
#vim weather.c
#include<stdio.h>
#include"soapH.h"
#include"ServiceSoap.nsmap"
#define
CITY_NAME "北京"
int main(int argc, char *argv[])
{
struct soap soap;
int ret = 0;
int element = 0;
int i = 0;
soap_init(&soap);
soap_set_mode(&soap, SOAP_C_UTFSTRING);
soap.mode |= SOAP_C_UTFSTRING;
struct _ns1__getWeatherbyCityName cityname;
struct _ns1__getWeatherbyCityNameResponse response;
cityname.theCityName = CITY_NAME;
cityname.theDayFlag = 0;
if(soap_call___ns3__getWeatherbyCityName(&soap, NULL, NULL,
&cityname, &response) == SOAP_OK)
{
printf("get weather ok !/n");
element = response.getWeatherbyCityNameResult->__sizestring;
for(i = 0; i < element; i++)
{
printf("i(%d), string(%s)/n", i,
response.getWeatherbyCityNameResult->string[i]);
}
}
else
{
printf("soap_call___ns3__getWeatherbyCityName failed!/n");
}
soap_destroy(&soap);
soap_end(&soap);
soap_done(&soap);
return 0;
}
6 編寫Makefile
#CROSS_COMPILER:=
CC:=$(CROSS_COMPILER)gcc
GCC:=$(CROSS_COMPILER)g++
all:
$(CC) -o weather weather.c soapC.c soapClient.c stdsoap2.c
clean:
rm -f weather
7 make , 執行程式
如果一切正常的話會出現有關天氣的資訊。
#./weather
get weather ok !
i(0), string((null))
i(1), string(北京)
i(2), string(晴)
i(3), string(7 ~ -4 ℃)
i(4), string(北風4-5級轉微風)
i(5), string(今天)
i(6), string(http://www.ayandy.com/images/晴.gif)
i(7), string((null))
常見問題:
1 程式編繹通過,但是運作./weather是失敗,列印soap_call___ns3__getWeatherbyCityName failed
答:可能是你的linux主機的網絡有問題,試試ping 一下其它網絡位址http://www.ayandy.com是否成功。
如何失敗,則可能的原因有:一, 網絡沒有連接配接到公網 二 dns 沒有設定。
2 我運作./weather後出現的列印為亂碼,如下
get weather ok !
i(0), string((null))
i(1), string(?漪)
i(2), string(??
i(3), string(7 ~ -4 ??
i(4), string(??4-5蝥扯蓮敺桅?)
i(5), string(隞予)
i(6), string(http://www.ayandy.com/images/??gif)
i(7), string((null))
答:這種情況是編碼格式不正确,伺服器傳回的是utf-8的字元品, 是以要求你的終端的設定的編碼格式也為utf-8.
(pietty的設定方法,option->Encoding->Unicode utf-8)
3 修改makefile 交叉編繹無法通過,出現列印stdsoap2.c:(.text+0x1b04c): undefined reference to `isnan'的錯誤。
答:将stdsoap.h裡1067行 # define soap_isnan(n) isnan(0) 修改為 # define soap_isnan(n) (0)