??xml version="1.0" encoding="utf-8" standalone="yes"?>久久精品国产亚洲AV香蕉,久久丝袜精品中文字幕,久久99国产精品二区不卡http://www.shnenglu.com/yeqing/category/2366.htmlzh-cnTue, 20 May 2008 12:55:01 GMTTue, 20 May 2008 12:55:01 GMT60Shell脚本调试技?/title><link>http://www.shnenglu.com/yeqing/articles/30919.html</link><dc:creator>夜沁</dc:creator><author>夜沁</author><pubDate>Mon, 27 Aug 2007 03:40:00 GMT</pubDate><guid>http://www.shnenglu.com/yeqing/articles/30919.html</guid><wfw:comment>http://www.shnenglu.com/yeqing/comments/30919.html</wfw:comment><comments>http://www.shnenglu.com/yeqing/articles/30919.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/yeqing/comments/commentRss/30919.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/yeqing/services/trackbacks/30919.html</trackback:ping><description><![CDATA[ 本文全面pȝCl了shell脚本调试技术,包括使用echo, tee, trap{命令输出关键信息,跟踪变量的|在脚本中植入调试钩子Q?#8220;-n”选项q行shell脚本的语法检查, 使用“-x”选项实现shell脚本逐条语句的跟t,巧妙地利用shell的内|变量增?#8220;-x”选项的输Z息等? 一. 前言 shell~程在unix/linux世界中用得非常q泛Q熟l掌握shell~程也是成ؓ一名优U的unix/linux开发者和pȝ理员的必经之\。脚本调试的主要工作是发现引发脚本错误的原因以及在脚本源代码中定位发生错误的行Q常用的手段包括分析输出的错误信息,通过在脚本中加入调试语句Q输试信息来辅助诊断错误Q利用调试工L。但与其它高U语a相比Qshell解释器缺乏相应的调试机制和调试工L支持Q其输出的错误信息又往往很不明确Q初学者在调试脚本Ӟ除了知道用echo语句输出一些信息外Q别无它法,而仅仅依赖于大量的加入echo语句来诊断错误,实令h不胜其繁Q故常见初学者抱怨shell脚本太难调试了。本文将pȝCl一些重要的shell脚本调试技术,希望能对shell的初学者有所裨益? 本文的目标读者是unix/linux环境下的开发h员,试人员和系l管理员Q要求读者具有基本的shell~程知识。本文所使用范例在Bash3.1+Redhat Enterprise Server 4.0下测试通过Q但所q调试技巧应也同样适用于其它shell? ? 在shell脚本中输试信? 通过在程序中加入调试语句把一些关键地Ҏ出错的地方的相关信息昄出来是最常见的调试手DcShellE序员通常使用echo(kshE序员常使用print)语句输出信息Q但仅仅依赖echo语句的输t信息很ȝQ调试阶D在脚本中加入的大量的echo语句在品交付时q得再费力一一删除。针对这个问题,本节主要介绍一些如何方便有效的输出调试信息的方法? 1. 使用trap命o trap命o用于捕获指定的信号ƈ执行预定义的命o? 其基本的语法? trap 'command' signal 其中signal是要捕获的信Pcommand是捕获到指定的信号之后,所要执行的命o。可以用kill –l命o看到pȝ中全部可用的信号名,捕获信号后所执行的命令可以是M一条或多条合法的shell语句Q也可以是一个函数名? shell脚本在执行时Q会产生三个所谓的“伪信?#8221;Q?之所以称之ؓ“伪信?#8221;是因三个信号是由shell产生的,而其它的信号是由操作pȝ产生?Q通过使用trap命o捕获q三?#8220;伪信?#8221;q输出相关信息对调试非常有帮助? ?1. shell伪信号信号名 何时产生 EXIT 从一个函C退出或整个脚本执行完毕 ERR 当一条命令返回非零状态时(代表命o执行不成? DEBUG 脚本中每一条命令执行之? 通过捕获EXIT信号,我们可以在shell脚本中止执行或从函数中退出时Q输出某些想要跟t的变量的|q由此来判断脚本的执行状态以及出错原?其用方法是Q? trap 'command' EXIT 或 trap 'command' 0 通过捕获ERR信号,我们可以方便的追t执行不成功的命令或函数Qƈ输出相关的调试信息,以下是一个捕获ERR信号的示例程序,其中?LINENO是一个shell的内|变量,代表shell脚本的当前行受?$ cat -n exp1.sh 1 ERRTRAP() 2 { 3 echo "[LINE:$1] Error: Command or function exited with status $?" 4 } 5 foo() 6 { 7 return 1; 8 } 9 trap 'ERRTRAP $LINENO' ERR 10 abc 11 foo 其输出结果如下:$ sh exp1.sh exp1.sh: line 10: abc: command not found [LINE:10] Error: Command or function exited with status 127 [LINE:11] Error: Command or function exited with status 1 在调试过E中Qؓ了跟t某些变量的|我们常常需要在shell脚本的许多地Ҏ入相同的echo语句来打印相兛_量的|q种做法昑־烦琐而笨拙。而通过捕获DEBUG信号Q我们只需要一条trap语句可以完成对相关变量的全E跟t? 以下是一个通过捕获DEBUG信号来跟t变量的CZE序:$ cat –n exp2.sh 1 #!/bin/bash 2 trap 'echo “before execute line:$LINENO, a=$a,b=$b,c=$c”' DEBUG 3 a=1 4 if [ "$a" -eq 1 ] 5 then 6 b=2 7 else 8 b=1 9 fi 10 c=3 11 echo "end" 其输出结果如下:$ sh exp2.sh before execute line:3, a=,b=,c= before execute line:4, a=1,b=,c= before execute line:6, a=1,b=,c= before execute line:10, a=1,b=2,c= before execute line:11, a=1,b=2,c=3 end 从运行结果中可以清晰的看到每执行一条命令之后,相关变量的值的变化。同Ӟ从运行结果中打印出来的行h分析Q可以看到整个脚本的执行轨迹Q能够判断出哪些条g分支执行了,哪些条g分支没有执行? 2. 使用tee命o 在shell脚本中管道以及输入输出重定向使用得非常多Q在道的作用下Q一些命令的执行l果直接成ؓ了下一条命令的输入。如果我们发现由道q接h的一批命令的执行l果q如预期的那样Q就需要逐步查各条命令的执行l果来判断问题出在哪儿,但因Z用了道Q这些中间结果ƈ不会昄在屏q上Q给调试带来了困难,此时我们可以借助于tee命o了? tee命o会从标准输入d数据Q将其内容输出到标准输出讑֤,同时又可内容保存成文g。例如有如下的脚本片D,其作用是获取本机的ip地址Q?ipaddr=`/sbin/ifconfig | grep 'inet addr:' | grep -v '127.0.0.1' | cut -d : -f3 | awk '{print $1}'` #注意=号后面的整句是用反引?数字1键的左边那个?括v来的? echo $ipaddr q行q个脚本Q实际输出的却不是本机的ip地址Q而是q播地址,q时我们可以借助tee命oQ输出某些中间结果,上q脚本片D修改ؓQ?ipaddr=`/sbin/ifconfig | grep 'inet addr:' | grep -v '127.0.0.1' | tee temp.txt | cut -d : -f3 | awk '{print $1}'` echo $ipaddr 之后Q将q段脚本再执行一遍,然后查看temp.txt文g的内容: $ cat temp.txt inet addr:192.168.0.1 Bcast:192.168.0.255 Mask:255.255.255.0 我们可以发现中间l果的第二列(列之间以:号分?才包含了IP地址Q而在上面的脚本中使用cut命o截取了第三列Q故我们只需脚本中的cut -d : -f3改ؓcut -d : -f2卛_得到正确的结果? 具体Cq的script例子Q我们也许ƈ不需要tee命o的帮助,比如我们可以分段执行q道连接v来的各条命oq查看各命o的输出结果来诊断错误Q但在一些复杂的shell脚本中,q些q道连接v来的命o可能又依赖于脚本中定义的一些其它变量,q时我们惌在提C符下来分段q行各条命o׃非常ȝ了,单地在管道之间插入一条tee命o来查看中间结果会更方便一些? 3. 使用"调试钩子" 在C语言E序中,我们l常使用DEBUG宏来控制是否要输试信息,在shell脚本中我们同样可以用这L机制Q如下列代码所C: if [ “$DEBUG” = “true” ]; then echo “debugging” #此处可以输出调试信息 fi q样的代码块通常UC?#8220;调试钩子”?#8220;调试?#8221;。在调试钩子内部可以输出M您想输出的调试信息,使用调试钩子的好处是它是可以通过DEBUG变量来控制的Q在脚本的开发调试阶D,可以先执行export DEBUG=true命o打开调试钩子Q其输试信息,而在把脚本交付用时Q也无需再费事把脚本中的调试语句一一删除? 如果在每一处需要输试信息的地方均用if语句来判断DEBUG变量的|q是昑־比较J琐Q通过定义一个DEBUG函数可以使植入调试钩子的q程更简z方便,如下面代码所C? $ cat –n exp3.sh 1 DEBUG() 2 { 3 if [ "$DEBUG" = "true" ]; then 4 $@   5 fi 6 } 7 a=1 8 DEBUG echo "a=$a" 9 if [ "$a" -eq 1 ] 10 then 11 b=2 12 else 13 b=1 14 fi 15 DEBUG echo "b=$b" 16 c=3 17 DEBUG echo "c=$c" 在上面所C的DEBUG函数中,会执行Q何传l它的命令,q且q个执行q程是可以通过DEBUG变量的值来控制的,我们可以把所有跟调试有关的命令都作ؓDEBUG函数的参数来调用Q非常的方便? 回页? ? 使用shell的执行选项 上一节所q的调试手段是通过修改shell脚本的源代码Qo其输出相关的调试信息来定位错误的Q那有没有不修改源代码来调试shell脚本的方法呢Q答案就是用shell的执行选项Q本节将介绍一些常用选项的用法: -n 只读取shell脚本Q但不实际执? -x q入跟踪方式Q显C所执行的每一条命? -c "string" 从strings中读取命? “-n”可用于测试shell脚本是否存在语法错误Q但不会实际执行命o。在shell脚本~写完成之后Q实际执行之前,首先使用“-n”选项来测试脚本是否存在语法错误是一个很好的习惯。因为某些shell脚本在执行时会对pȝ环境产生影响Q比如生成或Ud文g{,如果在实际执行才发现语法错误Q您不得不手工做一些系l环境的恢复工作才能l箋试q个脚本? “-c”选项使shell解释器从一个字W串中而不是从一个文件中dq执行shell命o。当需要时测试一段脚本的执行结果时Q可以用这个选项Q如下所C: sh -c 'a=1;b=2;let c=$a+$b;echo "c=$c"' "-x"选项可用来跟t脚本的执行Q是调试shell脚本的强有力工具?#8220;-x”选项使shell在执行脚本的q程中把它实际执行的每一个命令行昄出来Qƈ且在行首昄一?+"受?"+"号后面显C的是经q了变量替换之后的命令行的内容,有助于分析实际执行的是什么命令?“-x”选项使用h单方便,可以L对付大多数的shell调试d,应把其当作首选的调试手段? 如果把本文前面所q的trap ‘command’ DEBUG机制?#8220;-x”选项l合hQ我?可以既输出实际执行的每一条命令,又逐行跟踪相关变量的|对调试相当有帮助? 仍以前面所q的exp2.shZQ现在加?#8220;-x”选项来执行它Q?$ sh –x exp2.sh + trap 'echo "before execute line:$LINENO, a=$a,b=$b,c=$c"' DEBUG ++ echo 'before execute line:3, a=,b=,c=' before execute line:3, a=,b=,c= + a=1 ++ echo 'before execute line:4, a=1,b=,c=' before execute line:4, a=1,b=,c= + '[' 1 -eq 1 ']' ++ echo 'before execute line:6, a=1,b=,c=' before execute line:6, a=1,b=,c= + b=2 ++ echo 'before execute line:10, a=1,b=2,c=' before execute line:10, a=1,b=2,c= + c=3 ++ echo 'before execute line:11, a=1,b=2,c=3' before execute line:11, a=1,b=2,c=3 + echo end end 在上面的l果中,前面?#8220;+”L行是shell脚本实际执行的命令,前面?#8220;++”L行是执行trap机制中指定的命oQ其它的行则是输Z息? shell的执行选项除了可以在启动shell时指定外Q亦可在脚本中用set命o来指定?"set -参数"表示启用某选项Q?set +参数"表示关闭某选项。有时候我们ƈ不需要在启动时用"-x"选项来跟t所有的命o行,q时我们可以在脚本中使用set命oQ如以下脚本片段所C: set -x    #启动"-x"选项 要跟t的E序D? set +x     #关闭"-x"选项 set命o同样可以使用上一节中介绍的调试钩子—DEBUG函数来调用,q样可以避免脚本交付使用时删除这些调试语句的ȝQ如以下脚本片段所C: DEBUG set -x    #启动"-x"选项 要跟t的E序D? DEBUG set +x    #关闭"-x"选项 回页? ? ?-x"选项的增? "-x"执行选项是目前最常用的跟t和调试shell脚本的手D,但其输出的调试信息仅限于q行变量替换之后的每一条实际执行的命o以及行首的一?+"hC符Q居然连行号q样的重要信息都没有Q对于复杂的shell脚本的调试来_q是非常的不方便。幸q的是,我们可以巧妙地利用shell内置的一些环境变量来增强"-x"选项的输Z息,下面先介l几个shell内置的环境变量: $LINENO 代表shell脚本的当前行PcM于C语言中的内置宏__LINE__ $FUNCNAME 函数的名字,cM于C语言中的内置宏__func__,但宏__func__只能代表当前所在的函数名,?FUNCNAME的功能更强大Q它是一个数l变量,其中包含了整个调用链上所有的函数的名字,故变?{FUNCNAME[0]}代表shell脚本当前正在执行的函数的名字Q而变?{FUNCNAME[1]}则代表调用函?{FUNCNAME[0]}的函数的名字Q余者可以依此类推? $PS4 LC符变量$PS1和第二提示W变?PS2比较常见Q但很少有h注意到第四提示W变?PS4的作用。我们知道?#8220;-x”执行选项会昄shell脚本中每一条实际执行过的命令,?PS4的值将被显C在“-x”选项输出的每一条命令的前面。在Bash Shell中,~省?PS4的值是"+"受?现在知道Z么?-x"选项Ӟ输出的命令前面有一?+"号了吧?)? 利用$PS4q一Ҏ,通过使用一些内|变量来重定?PS4的|我们可以增?-x"选项的输Z息。例如先执行export PS4='+{$LINENO:${FUNCNAME[0]}} ', 然后再?#8220;-x”选项来执行脚本,p在每一条实际执行的命o前面昄其行号以及所属的函数名? 以下是一个存在bug的shell脚本的示例,本文用此脚本来C如何?#8220;-n”以及增强?#8220;-x”执行选项来调试shell脚本。这个脚本中定义了一个函数isRoot(),用于判断当前用户是不是root用户Q如果不是,则中止脚本的执行 $ cat –n exp4.sh 1 #!/bin/bash 2 isRoot() 3 { 4 if [ "$UID" -ne 0 ] 5 return 1 6 else 7 return 0 8 fi 9 } 10 isRoot 11 if ["$?" -ne 0 ] 12 then 13 echo "Must be root to run this script" 14 exit 1 15 else 16 echo "welcome root user" 17 #do something 18 fi 首先执行sh –n exp4.sh来进行语法检查,输出如下Q?$ sh –n exp4.sh exp4.sh: line 6: syntax error near unexpected token `else' exp4.sh: line 6: ` else' 发现了一个语法错误,通过仔细查第6行前后的命oQ我们发现是W?行的if语句~少then关键字引L(写惯了CE序的h很容易犯q个错误)。我们可以把W?行修改ؓif [ "$UID" -ne 0 ]; then来修正这个错误。再ơ运行sh –n exp4.sh来进行语法检查,没有再报告错误。接下来可以实际执行这个脚本了Q执行结果如下: $ sh exp4.sh exp2.sh: line 11: [1: command not found welcome root user 管脚本没有语法错误了,在执行时却又报告了错误。错误信息还非常奇?#8220;[1: command not found”。现在我们可以试试定?PS4的|q?#8220;-x”选项来跟t: $ export PS4='+{$LINENO:${FUNCNAME[0]}} ' $ sh –x exp4.sh +{10:} isRoot +{4:isRoot} '[' 503 -ne 0 ']' +{5:isRoot} return 1 +{11:} '[1' -ne 0 ']' exp4.sh: line 11: [1: command not found +{16:} echo 'welcome root user' welcome root user 从输出结果中Q我们可以看到脚本实际被执行的语句,该语句的行号以及所属的函数名也被打印出来,从中可以清楚的分析出脚本的执行轨q以及所调用的函数的内部执行情况。由于执行时是第11行报错,q是一个if语句Q我们对比分析一下同为if语句的第4行的跟踪l果Q?+{4:isRoot} '[' 503 -ne 0 ']' +{11:} '[1' -ne 0 ']' 可知׃W?1行的[号后面缺了一个空|D[号与紧挨它的变量$?的?被shell解释器看作了一个整体,q试着把这个整体视Z个命令来执行Q故?#8220;[1: command not found”q样的错误提C。只需在[号后面插入一个空格就一切正怺? shell中还有其它一些对调试有帮助的内置变量Q比如在Bash Shell中还有BASH_SOURCE, BASH_SUBSHELL{一批对调试有帮助的内置变量Q您可以通过man sh或man bash来查看,然后Ҏ您的调试目的,使用q些内置变量来定?PS4Q从而达到增?#8220;-x”选项的输Z息的目的? ? ȝ 现在让我们来ȝ一下调试shell脚本的过E: 首先使用“-n”选项查语法错误,然后使用“-x”选项跟踪脚本的执行,使用“-x”选项之前Q别忘了先定制PS4变量的值来增强“-x”选项的输Z息,臛_应该令其输出行号信息(先执行export PS4='+[$LINENO]'Q更一x逸的办法是将q条语句加到您用户主目录?bash_profile文g中去)Q这你的调试之旅更轻松。也可以利用trap,调试钩子{手D输出关键调试信息,快速羃排查错误的范围Qƈ在脚本中使用“set -x”?#8220;set +x”Ҏ些代码块q行重点跟踪。这样多U手D齐下,怿您已l可以比较轻村֜抓出您的shell脚本中的臭虫了。如果您的脚本够复杂,q需要更强的调试能力Q可以用shell调试器bashdbQ这是一个类gGDB的调试工P可以完成对shell脚本的断点设|,单步执行Q变量观察等许多功能Q用bashdb寚wd理解复杂的shell脚本也会大有裨益。关于bashdb的安装和使用Q不属于本文范围Q您可参阅http://bashdb.sourceforge.net/上的文档q下载试用? 参考资? 误问: GNU ?bash 主页 请下载和试用 Shell调试器bashdb<img src ="http://www.shnenglu.com/yeqing/aggbug/30919.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/yeqing/" target="_blank">夜沁</a> 2007-08-27 11:40 <a href="http://www.shnenglu.com/yeqing/articles/30919.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux命o行程序设?/title><link>http://www.shnenglu.com/yeqing/articles/15768.html</link><dc:creator>夜沁</dc:creator><author>夜沁</author><pubDate>Wed, 29 Nov 2006 01:29:00 GMT</pubDate><guid>http://www.shnenglu.com/yeqing/articles/15768.html</guid><wfw:comment>http://www.shnenglu.com/yeqing/comments/15768.html</wfw:comment><comments>http://www.shnenglu.com/yeqing/articles/15768.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/yeqing/comments/commentRss/15768.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/yeqing/services/trackbacks/15768.html</trackback:ping><description><![CDATA[ <p> <font color="#808080" size="2">Linux下很多程序甚至那些具有图形用L面(graphical user interfaceQGUIQ的E序Q都能接受和处理命o行选项。对于某些程序,q是与其他程序或用户q行交互的主要手Dc具有可靠的复杂命o行参数处理机Ӟ会得您的应用程序更好、更有用。不q很多开发h员都其宝贵的时间花在了~写自己的命令行解析器,却不使用 getopt()Q而后者是一个专门设计来减轻命o行处理负担的库函数?/font> </p> <p> <font color="#808080" size="2"> </font> </p> <p> <font color="#808080" size="2">1、命令行参数<br />命o行程序设计的首要d是解析命令行参数QGUIzE序员很关心这个。这里,我们对参敎ͼargumentQ采用了一U比较通俗的定义:命o行上除命令名之外的字W串。参数由多项构成Q项与项之间用空白符彼此隔开?br />参数q一步分为选项和操作数。选项用于修改E序的默认行为或为程序提供信息,比较老的U定是以短划U开头。选项后可以跟随一些参敎ͼUCؓ选项参数。剩下的是操作C?br />2、POSIXU定<br />POSIX表示可移植操作系l接口:Portable Operating System InterfaceQ电气和电子工程师协会(Institute of Electrical and Electronics EngineersQIEEEQ最初开?POSIX 标准Q是Z提高 UNIX 环境下应用程序的可移植性。然而,POSIX q不局限于 UNIX。许多其它的操作pȝQ例?DEC OpenVMS ?Microsoft Windows NTQ都支持 POSIX 标准?br /> </font> </p> <p> <font color="#808080" size="2">下面是POSIX标准中关于程序名、参数的U定Q?/font> </p> <p> <font color="#808080" size="2">E序名不宜少?个字W且不多?个字W; <br />E序名应只包含小写字母和阿拉伯数字; <br />选项名应该是单字W活单数字,且以短横?‘ؓ前綴Q?<br />多个不需要选项参数的选项Q可以合q。(譬如Qfoo -a -b -c ---->foo -abcQ?<br />选项与其参数之间用空白符隔开Q?<br />选项参数不可选?<br />若选项参数有多|要将其ƈ未一个字串传q来。譬如:myprog -u "arnold,joe,jane"。这U情况下Q需要自p册些参数的分离问题?<br />选项应该在操作数出现之前出现?<br />Ҏ参数?-'指明所有参数都l束了,其后M参数都认为是操作数?<br />选项如何排列没有什么关p,但对互相排斥的选项Q如果一个选项的操作结果覆盖其他选项的操作结果时Q最后一个选项起作用;如果选项重复Q则序处理?<br />允许操作数的序影响E序行ؓQ但需要作文档说明?<br />d指定文g的程序应该将单个参数'-'作ؓ有意义的标准输入或输出来对待?br />当然许多标准从恒许未遵守以上U定Q主要是历史兼容问题Q因为标准出C前,已l存在N多程序了?/font> </p> <p> <font color="#808080" size="2">3、GNU镉K项<br />GNU鼓励E序员?-help?-verbose{Ş式的镉K项。这些选项不仅不与POSIXU定冲突Q而且Ҏ记忆Q另外也提供了在所有GNU工具之间保持一致性的Z。GNU镉K项有自qU定Q?/font> </p> <p> <font color="#808080" size="2">对于已经遵@POSIXU定的GNUE序Q每个短选项都有一个对应的镉K项?<br />额外针对GNU的长选项不需要对应的短选项Q仅仅推荐要有?<br />镉K项可以~写成保持惟一性的最短的字串?<br />选项参数与长选项之间或通过I白字符z通过一?='来分隔?<br />选项参数是可选的Q只对短选项有效Q?<br />镉K项允许以一个短横线为前~?/font> </p> <p> <font color="#808080" size="2">4、基本的命o行处理技?br />CE序通过argc和argv参数讉K它的命o行参数。argc是整型数Q表C参数的个数Q包括命令名Q。main()函数的定义方式有两种Q区别仅在于argv如何定义Q?/font> </p> <p> <font color="#808080" size="2">int main(int argc, char *argv[])<br />{<br />   …?br />} int main(int argc, char **argv)<br />{<br />   …?br />}  </font> </p> <p> <br /> <font color="#808080" size="2">?C q行时库的程序启动代码调用您?main() Ӟ已经对命令行q行了处理。argc 参数包含参数的计数|?argv 包含指向q些参数的指针数l。argv[0]是程序名?/font> </p> <p> <font color="#808080" size="2">一个很单的命o行处理技术的例子是echoE序Q它可以参数输出到标准讑֤上,用空格符隔开Q最后换行。若命o行第一个参Cؓ-nQ那么就不会换行?/font> </p> <p> <font color="#808080" size="2">清单1Q?/font> </p> <p> <font color="#808080" size="2">#include <stdio.h></font> </p> <p> <font color="#808080" size="2">int main(int argc, char **argv)<br />{<br />    int i, nflg;</font> </p> <p> <font color="#808080" size="2">    nflg = 0;<br />    if(argc > 1 && argv[1][0] == '-' && argv[1][1] == 'n'){<br />        nflg++;<br />        argc--;<br />        argv++;<br />    }<br />    for(i=1; i<argc; i++){<br />        fputs(argv[ i ], stdout);<br />        if(i < argc-1)<br />            putchar(' ');<br />    }<br />    if(nflg == 0)<br />        putchar('\n');</font> </p> <p> <font color="#808080" size="2">    return 0;<br />}<br /> </font> </p> <p> <font color="#808080" size="2">上面代码中,加亮区域仔细研究一下,会发现很有趣?/font> </p> <p> <font color="#808080" size="2">echoE序中,对于命o行参数的解析是手动实现的。很久以前,Unix支持组Z化对于命令行参数的解析,开发了getopt()函数Q同时提供了几个外部变量Q得编写遵守POSIX的代码变得更加容易了?/font> </p> <p> <font color="#808080" size="2">5、命令行参数解析函数 —?getopt()<br />getopt()函数声明如下Q?/font> </p> <p> <font color="#808080" size="2">#include <unistd.h></font> </p> <p> <font color="#808080" size="2">int getopt(int argc, char * const argv[], const char *optstring);</font> </p> <p> <font color="#808080" size="2">extern char *optarg;<br />extern int optind, opterr, optopt;<br /> </font> </p> <p> <font color="#808080" size="2">该函数的argc和argv参数通常直接从main()的参数直接传递而来。optstring是选项字母l成的字丌Ӏ如果该字串里的M字符后面有冒P那么q个选项p求有选项参数?/font> </p> <p> <font color="#808080" size="2">当给定getopt()命o参数的数?(argc)、指向这些参数的数组 (argv) 和选项字串 (optstring) 后,getopt() 返回第一个选项Qƈ讄一些全局变量。用相同的参数再次调用该函数时Q它返回下一个选项Qƈ讄相应的全局变量。如果不再有可识别的选项Q将q回 -1Q此d完成了?/font> </p> <p> <font color="#808080" size="2">getopt() 所讄的全局变量包括Q?/font> </p> <p> <font color="#808080" size="2">char *optarg——当前选项参数字串Q如果有Q?<br />int optind——argv的当前烦引倹{当getopt()在while循环中用时Q@环结束后Q剩下的字串视ؓ操作敎ͼ在argv[optind]至argv[argc-1]中可以找到?<br />int opterr——这个变量非零时Qgetopt()函数为“无效选项”和“缺参数选项Qƈ输出光误信息?/font> </p> <p> <font color="#808080" size="2">int optopt——当发现无效选项字符之时Qgetopt()函数或返??'字符Q或q回':'字符Qƈ且optopt包含了所发现的无效选项字符?br />下面qgetopt()来写个小E序Q体验一下命令行解析的快乐?/font> </p> <p> <font color="#808080" size="2">E序描述Q?/font> </p> <p> <font color="#808080" size="2">E序名:opt_parse_demo</font> </p> <p> <font color="#808080" size="2">选项Q?/font> </p> <p> <font color="#808080" size="2">-n —?昄我的名字?<br />-g —?昄我女朋友的名字?<br />-l —?带参数的选项.<br />清单2Q?br />#include <stdio.h><br />#include <unistd.h></font> </p> <p> <font color="#808080" size="2">int main (int argc, char **argv)<br />{<br />    int oc;                     /*选项字符 */<br />    char *b_opt_arg;            /*选项参数字串 */</font> </p> <p> <font color="#808080" size="2">    while((oc = getopt(argc, argv, "ngl:")) != -1)<br />    {<br />        switch(oc)<br />        {<br />            case 'n':<br />                printf("My name is Lyong.\n");<br />                break;<br />            case 'g':<br />                printf("Her name is Xxiong.\n");<br />                break;<br />            case 'l':<br />                b_opt_arg = optarg;<br />                printf("Our love is %s\n", optarg);<br />                break;<br />        }<br />    }<br />   return 0;<br />}<br /> </font> </p> <p> <font color="#808080" size="2">q行l果Q?/font> </p> <p> <font color="#808080" size="2">$ ./opt_parse_demo -n<br />My name is Lyong.<br />$ ./opt_parse_demo -g<br />Her name is Xxiong.<br />$ ./opt_parse_demo -l forever<br />Our love is forever<br />$ ./opt_parse_demo -ngl forever<br />My name is Lyong.<br />Her name is Xxiong.<br />Our love is forever<br /> </font> </p> <p> <font color="#808080" size="2">6、改变getopt()寚w误命令行参数信息的输?br />不正的调用E序在所隑օQ这U错误要么是命o行选项无效Q要么是~少选项参数。正常情况下Qgetopt()会ؓq两U情况输q出错信息Qƈ且返??'。ؓ了验证此事,可以修改一下上面的清单2中的代码?/font> </p> <p> <font color="#808080" size="2">清单3Q?/font> </p> <p> <font color="#808080" size="2">#include <stdio.h><br />#include <unistd.h></font> </p> <p> <font color="#808080" size="2">int main (int argc, char **argv)<br />{<br />    int oc;                     /*选项字符 */<br />    char *b_opt_arg;            /*选项参数字串 */</font> </p> <p> <font color="#808080" size="2">    while((oc = getopt(argc, argv, "ngl:")) != -1)<br />    {<br />        switch(oc)<br />        {<br />            case 'n':<br />                printf("My name is Lyong.\n");<br />                break;<br />             case 'g':<br />                printf("Her name is Xxiong.\n");<br />                break;<br />            case 'l':<br />                b_opt_arg = optarg;<br />                printf("Our love is %s\n", optarg);<br />                break;<br />            case '?':<br />                printf("arguments error!\n");<br />                break;<br />        }<br />    }<br />    return 0;<br />}<br /> </font> </p> <p> <font color="#808080" size="2">输入一个错误的命o行,l果如下Q?/font> </p> <p> <font color="#808080" size="2">$ ./opt_parse_demo -l<br />./opt_parse_demo: option requires an argument -- l<br />arguments error!<br /> </font> </p> <p> <font color="#808080" size="2">很多时候,我们不希望输ZQ何错误信息,或更希望输出自己定义的错误信息。可以采用以下两U方法来更改getopt()函数的出错信息输为:</font> </p> <p> <br /> <font color="#808080" size="2">在调用getopt()之前Q将opterr讄?Q这样就可以在getopt()函数发现错误的时候强制它不输ZQ何消息?<br />如果optstring参数的第一个字W是冒号Q那么getopt()函数׃保持沉默QƈҎ错误情况q回不同字符Q如下: <br />“无效选项?—?getopt()q回'?'Qƈ且optopt包含了无效选项字符Q这是正常的行ؓQ?<br />“缺选项参数?—?getopt()q回':'Q如果optstring的第一个字W不是冒P那么getopt()q回'?'Q这会得这U情况不能与无效选项的情况区分开?br />多说无益Q动手测试一下?/font> </p> <p> <font color="#808080" size="2">清单4Q?br />#include <stdio.h><br />#include <unistd.h></font> </p> <p> <font color="#808080" size="2">int main (int argc, char **argv)<br />{<br />    int oc;                     /*选项字符 */<br />    char ec;                             /*无效的选项字符*/<br />    char *b_opt_arg;            /*选项参数字串 */</font> </p> <p> <font color="#808080" size="2">    while((oc = getopt(argc, argv, ":ngl:")) != -1)<br />    {<br />        switch(oc)<br />        {<br />            case 'n':<br />                printf("My name is Lyong.\n");<br />                break;<br />             case 'g':<br />                printf("Her name is Xxiong.\n");<br />                break;<br />            case 'l':<br />                b_opt_arg = optarg;<br />                printf("Our love is %s\n", optarg);<br />                break;<br />            case '?':<br />                ec = (char)optopt;<br />                printf("无效的选项字符 \' %c \'!\n", ec);<br />                break;<br />            case ':':<br />                printf("~少选项参数Q\n");<br />                break;<br />        }<br />    }<br />    return 0;<br />} </font> </p> <p> <font color="#808080" size="2">试l果Q?/font> </p> <p> <font color="#808080" size="2">$ ./opt_parse_demo -a<br />无效的选项字符 ' a '!<br />$ ./opt_parse_demo -l<br />~少选项参数Q?</font> </p> <p> <font color="#808080" size="2">7、GNU提供的getopt()函数的特?br />上面所设计的getopt()函数是UNIX支持组提供的,其执行时一到不以'-'开始的命o行参数就停止L选项。而GNU提供的getopt()函数与之不同Q它会扫描整个命令行来寻N项。当调用GNU getopt()函数q处理命令行参数的时候,它重新排列argv中的元素Q这样当重排l束Ӟ所有选项都被Ud到前面ƈ且那些l检查argv[optind]至argv[argc-1]中剩余参数的代码仍正常工作,但在M情况下,到Ҏ参数'--'q束对选项的扫描?/font> </p> <p> <font color="#808080" size="2">可以输入一个ؕ序的命o行,查看opt_parse_demo的输出:</font> </p> <p> <font color="#808080" size="2">$ ./opt_parse_demo -l forever a b c d -g -n<br />Our love is forever<br />Her name is Xxiong.<br />My name is Lyong.<br /> </font> </p> <p> <font color="#808080" size="2">GNU getopt()W二个特Ҏ可以在optstring中用特D的首字W改变getopt()的默认行为:</font> </p> <p> <font color="#808080" size="2">optstring[0] = '+'Q这样就与UNIX支持组提供的getopt()很相q了?<br />optstring[0] = '-'Q会在optarg中得到命令行中的每个参数?<br />以上两种情况下,':'可以作ؓW二个字W用?br />GNU getopt()W三个特Ҏoptstring中的选项字符后面接两个冒P允许该选项有可选的选项参数。在选项参数不存在的情况下,GNU getopt()q回选项字符q将optarg讄为NULL?/font> </p> <p> <font color="#808080" size="2">8、GNU镉K项命o行解?br />20 世纪 90 q代QUNIX 应用E序开始支持长选项Q即一对短横线、一个描q性选项名称Q还可以包含一个用等可接到选项的参数?/font> </p> <p> <font color="#808080" size="2">GNU提供了getopt-long()和getopt-long-only()函数支持镉K项的命令行解析Q其中,后者的镉K项字串是以一个短横线开始的Q而非一对短横线?/font> </p> <p> <br /> <font color="#808080" size="2">getopt_long() 是同时支持长选项和短选项?getopt() 版本。下面是它们的声明:</font> </p> <p> <font color="#808080" size="2">#include <getopt.h></font> </p> <p> <font color="#808080" size="2">int getopt_long(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex);</font> </p> <p> <font color="#808080" size="2">int getopt_long_only(int argc, char * const argv[],const char *optstring,const struct option *longopts, int *longindex);</font> </p> <p> <font color="#808080" size="2"> </font> </p> <p> <font color="#808080" size="2">getopt_long()的前三个参数与上面的getopt()相同Q第4个参数是指向optionl构的数l,optionl构被称为“长选项表”。longindex参数如果没有讄为NULLQ那么它指向一个变量,q个变量会被赋gؓL到的镉K项在longopts中的索引|q可以用于错误诊断?/font> </p> <p> <font color="#808080" size="2">optionl构在getopt.h中的声明如下Q?/font> </p> <p> <font color="#808080" size="2">struct option{<br />    const char *name;<br />    int has_arg;<br />    int *flag;<br />    int val;<br />};<br /> </font> </p> <p> <font color="#808080" size="2">对结构中的各元素解释如下Q?/font> </p> <p> <font color="#808080" size="2">const char *name<br />q是选项名,前面没有短横Uѝ譬?help"?verbose"之类?/font> </p> <p> <font color="#808080" size="2">int has_arg<br />描述了选项是否有选项参数。如果有Q是哪种cd的参敎ͼ此时Q它的g定是下表中的一个?/font> </p> <p> <font color="#808080" size="2">W号帔R  数值?含义  <br />no_argument  0 选项没有参数  <br />required_argument 1 选项需要参?<br /> <br />optional_argument 2 选项参数可选?</font> </p> <p> <font color="#808080" size="2">int *flag<br />如果q个指针为NULLQ那么getopt_long()q回该结构val字段中的数倹{如果该指针不ؓNULLQgetopt_long()会得它所指向的变量中填入val字段中的数|q且getopt_long()q回0。如果flag不是NULLQ但未发现长选项Q那么它所指向的变量的数g变?/font> </p> <p> <font color="#808080" size="2">int val<br />q个值是发现了长选项时的q回|或者flag不是NULL时蝲?flag中的倹{典型情况下Q若flag不是NULLQ那么val是个真/假|譬如1?Q另一斚wQ如果flag是NULLQ那么val通常是字W常量,若长选项与短选项一_那么该字W常量应该与optstring中出现的q个选项的参数相同?/font> </p> <p> <font color="#808080" size="2">每个镉K项在长选项表中都有一个单独条目,该条目里需要填入正的数倹{数l中最后的元素的值应该全?。数l不需要排序,getopt_long()会进行线性搜索。但是,Ҏ长名字来排序会ɽE序员读h更容易?/font> </p> <p> <font color="#808080" size="2">以上所说的flag和val的用法看上去有点混ؕQ但它们很有实用价|因此有必要搞透彻了?/font> </p> <p> <font color="#808080" size="2">大部分时候,E序员会Ҏgetopt_long()发现的选项Q在选项处理q程中要讄一些标记变量,譬如在用getopt()Ӟl常做出如下的程序格式:</font> </p> <p> <font color="#808080" size="2">int do_name, do_gf_name, do_love; /*标记变量*/<br />char *b_opt_arg;</font> </p> <p> <font color="#808080" size="2">while((c = getopt(argc, argv, ":ngl:")) != -1)<br />{<br />    switch (c){<br />    case 'n':<br />        do_name = 1;<br />    case 'g':<br />        do_gf_name = 1;<br />        break;<br />        break;<br />    case 'l':<br />        b_opt_arg = optarg;<br />    …?br />    }<br />}<br /> </font> </p> <p> <font color="#808080" size="2">当flag不ؓNULLӞgetopt_long*()会ؓ你设|标记变量。也是说上面的代码中,关于选项'n'?l'的处理,只是讄一些标讎ͼ如果flag不ؓNULL,Ӟgetopt_long()可以自动为各选项所对应的标记变量设|标讎ͼq样p够将上面的switch语句中的两种U情况减到了一U。下面给Z个长选项表以及相应处理代码的例子?/font> </p> <p> <font color="#808080" size="2">清单5Q?/font> </p> <p> <font color="#808080" size="2">#include <stdio.h><br />#include <getopt.h></font> </p> <p> <font color="#808080" size="2">int do_name, do_gf_name;<br />char *l_opt_arg;</font> </p> <p> <font color="#808080" size="2">struct option longopts[] = {<br />    { "name",        no_argument,            &do_name,        1    },<br />    { "gf_name",    no_argument,            &do_gf_name,    1    },<br />    { "love",        required_argument,    NULL,                'l'    },<br />    {     0,    0,    0,    0},<br />};</font> </p> <p> <font color="#808080" size="2">int main(int argc, char *argv[])<br />{<br />    int c;<br />    <br />    while((c = getopt_long(argc, argv, ":l:", longopts, NULL)) != -1){<br />        switch (c){<br />        case 'l':<br />            l_opt_arg = optarg;<br />            printf("Our love is %s!\n", l_opt_arg);<br />            break;<br />        case 0:<br />            printf("getopt_long()讄变量 : do_name = %d\n", do_name);<br />            printf("getopt_long()讄变量 : do_gf_name = %d\n", do_gf_name);<br />            break;<br />        }<br />    }<br />    return 0;<br />}<br /> </font> </p> <p> <font color="#808080" size="2">在进行测试之前,再来回顾一下有关optionl构中的指针flag的说明吧?/font> </p> <p> <font color="#808080" size="2">如果q个指针为NULLQ那么getopt_long()q回该结构val字段中的数倹{如果该指针不ؓNULLQgetopt_long()会得它所指向的变量中填入val字段中的数|q且getopt_long()q回0。如果flag不是NULLQ但未发现长选项Q那么它所指向的变量的数g变?</font> </p> <p> <font color="#808080" size="2">下面试一下:</font> </p> <p> <font color="#808080" size="2">$ ./long_opt_demo --name<br />getopt_long()讄变量 : do_name = 1<br />getopt_long()讄变量 : do_gf_name = 0</font> </p> <p> <font color="#808080" size="2">$ ./long_opt_demo --gf_name<br />getopt_long()讄变量 : do_name = 0<br />getopt_long()讄变量 : do_gf_name = 1</font> </p> <p> <font color="#808080" size="2">$ ./long_opt_demo --love forever<br />Our love is forever!</font> </p> <p> <font color="#808080" size="2">$ ./long_opt_demo -l forever<br />Our love is forever!</font> </p> <p> <font color="#808080" size="2"> </font> </p> <p> <font color="#808080" size="2">试q后Q应该有所感触了。关于flag和val的讨论到此ؓ止。下面ȝ一下get_long()的各U返回值的含义Q?/font> </p> <p> <font color="#808080" size="2">q回值  ?<br /> ??br /> <br />0      <br /> getopt_long()讄一个标志,它的goptionl构中的val字段的g?br /> <br />1<br /> 每碰C个命令行参数Qoptarg都会记录?br /> <br />'?'<br /> 无效选项<br /> <br />':'<br /> ~少选项参数<br /> <br />'x'<br /> 选项字符'x'<br /> <br />-1<br /> 选项解析l束<br /> </font> </p> <p> <font color="#808080" size="2">从实用的角度来说Q我们更期望每个镉K项都对应一个短选项Q这U情况下Q在optionl构中,只要flag讄为NULLQƈval讄为长选项所对应的短选项字符卛_。譬如上面清?中的E序Q我们修改如下?/font> </p> <p> <font color="#808080" size="2">清单6Q?br />#include <stdio.h><br />#include <getopt.h></font> </p> <p> <font color="#808080" size="2">int do_name, do_gf_name;<br />char *l_opt_arg;</font> </p> <p> <font color="#808080" size="2">struct option longopts[] = {<br />    { "name",        no_argument,            NULL,                'n'    },<br />    { "gf_name",    no_argument,            NULL,                'g'    },<br />    { "love",        required_argument,    NULL,                'l'    },<br />    {     0,    0,    0,    0},<br />};</font> </p> <p> <font color="#808080" size="2">int main(int argc, char *argv[])<br />{<br />    int c;<br />    <br />    while((c = getopt_long(argc, argv, ":l:", longopts, NULL)) != -1){<br />        switch (c){<br />        case 'n':<br />            printf("My name is LYR.\n");<br />            break;<br />        case 'g':<br />            printf("Her name is BX.\n");<br />            break;<br />        case 'l':<br />            l_opt_arg = optarg;<br />            printf("Our love is %s!\n", l_opt_arg);<br />            break;<br />        }<br />    }<br />    return 0;<br />} </font> </p> <p> <font color="#808080" size="2">试l果如下Q?/font> </p> <p> <br /> <font color="#808080" size="2">$ ./long_opt_demo --name --gf_name --love forever<br />My name is LYR.<br />Her name is BX.<br />Our love is forever!</font> </p> <p> <font color="#808080" size="2">$ ./long_opt_demo -ng -l forever<br />My name is LYR.<br />Her name is BX.<br />Our love is forever!<br /> </font> </p> <p> <font color="#808080" size="2">9、在LINUX之外的系l^C使用GNU getopt()或getopt_long()<br />只要从GNUE序或GNU C Library(GLIBC)的CVS档案文g中copy源文件即可(</font> <a > <font color="#808080" size="2">http://sourceware.org/glibc/</font> </a> <font color="#808080" size="2">Q。所需源文件是getopt.h、getopt.c和getoptl.cQ将q些文g包含在你的项目中。另外,你的目中最好也COPYING.LIB文g包含q去Q因为GNU LGPLQGNU E序库公p可证Q的内容全部包括在命名ؓCOPYING.LIB 的文件中。没事时Q可以阅M下自pY件的许可协议Q感受一下雷锋精?/font> </p> <p> <font color="#808080" size="2">注意Q在包含所需文g之后Q在调用getopt_long()pd函数的源代码中,应该使用#include "getopt.h"Q而不?include <getopt.h>Q前者会首先在当前目录中Lgetopt.h?/font> </p> <p> <font color="#808080" size="2">使用Windowsq_的兄弟可以试用一下,很希望能在这里反馈一下你的用情况,谢谢?/font> </p> <p> <br /> <font color="#808080" size="2">10、结?br />E序需要能够快速处理各个选项和参敎ͼ且要求不会浪费开发h员的太多旉。在q一点上Q无论是GUI(囑Ş用户交互Q程序还是CUIQ命令行交互Q程序,都是光要Q务,其区别仅在于实现方式的不同。GUI通过菜单、对话框之类的图形控件来完成交互Q而CUI使用了纯文本的交互方式。各有利弊吧。在E序开发中Q许多测试程序用CUI来完成是首选方案?/font> </p> <p> <font color="#808080" size="2">getopt() 函数是一个标准库调用Q可允许您用直接的 while/switch 语句方便地逐个处理命o行参数和选项Q带或不带附加的参数Q。与其类似的 getopt_long() 允许在几乎不q行额外工作的情况下处理更具描述性的镉K项Q这非常受开发h员的Ƣ迎?</font> </p> <p> <font color="#808080" size="2">既然已经知道了如何方便地处理命o行选项Q现在就可以集中_֊改进您的E序的命令行Q可以添加长选项支持Q或d之前׃不想向程序添加额外的命o行选项处理而搁|的M其他选项。但不要忘记在某处记录您所有的选项和参敎ͼq提供某U类型的内置帮助函数来ؓ健忘的用h供帮助?/font> </p> <img src ="http://www.shnenglu.com/yeqing/aggbug/15768.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/yeqing/" target="_blank">夜沁</a> 2006-11-29 09:29 <a href="http://www.shnenglu.com/yeqing/articles/15768.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>gSOAP学习体会http://www.shnenglu.com/yeqing/articles/12762.html夜沁夜沁Wed, 20 Sep 2006 08:21:00 GMThttp://www.shnenglu.com/yeqing/articles/12762.htmlhttp://www.shnenglu.com/yeqing/comments/12762.htmlhttp://www.shnenglu.com/yeqing/articles/12762.html#Feedback4http://www.shnenglu.com/yeqing/comments/commentRss/12762.htmlhttp://www.shnenglu.com/yeqing/services/trackbacks/12762.html 前一阶段写gSOAP 的文章没保存好,后来惛_的,学没有写的勇气了Q感觉自己很菜,但是现在感觉q是写点ql入门者一ҎC吧。另外虽说这文章是自己写的Q但是却感觉是东D凑的Q有很多别h的东西了?br />   看了我{载的关于soap 的文章,大家惛_对soap有所了解了吧Q那么gSOAP是什么那Q?br />gSOAP是一个开源的目Q用它可以方便的使用c/c++地进行SOAP客户端和服务器端~程Q而不必了解xml和SOAP协议的细节。这样用者就可以专注于自qweb service 客户端或服务器端的编写,而不用纠~与其它l节。我W一ơ接触这些东西,我对SOAP的理解是q样的:以http协议为基本的通信协议Q以xml文g形式hq程服务Q再以xml文g的Ş式返回执行结果,我理解的p么简单了Q有啥不妥处Q还h教阿?br />实践一下才有理性认识,下面是我自己在windows下,具体说来是用vc 6.0下编写的一个很单的客户端程序调用远E的服务Q来发送电子邮Ӟ感觉很爽吧?br />首先我们?/font> http://sourceforge.net/project/showfiles.php?group_id=52781 下蝲gSOAP下蝲工具集吧Q不同的pȝ下用的gSOAP是不一LQ根据需要下载了windows下的和linux下的?br />gSOAP工具集不需要安装,直接解压可以了。在/bin目录下我们可以看C个可执行文gQ?br />soapcpp2.exe: gSOAP~译器,~译头文件生成服务器和客L都需要的 c/c++文g?
wsdl2h.exe: ~译wsdl文g生成c/c++头文件?br />工具q准备好了?br />其次Q我们到
http://www.abysal.com/soap/AbysalEmail.wsdl 下蝲
wsdl文gQ假设保存文件名为:AbysalEmail.wsdl。所谓的wsdl文g译成中
文就是网l服务描q文件了。我们用wsdl2h.exe工具来根据wsdl文g生成
c/c++头文Ӟ可以?c选项是生成纯c的头文gQ另外用-s选项是说明我们在
E序中不使用stlQ注意了默认我们是适用stl的?br />用如下命令:
wsdl2h  -o AbysalEmail.h AbysalEmail.wsdl
既可以生成我们需要的AbysalEmail.h头文件了。这里文件名可以随便起了?br />下载的gsoap的import里的stlvector.h中文件拷贝到当前的文件夹下,因ؓ默认是用stl的,所以需要它?br />然后执行soapcpp2 命o来生成存根程序,用如下命令:
soapcpp2  -C AbysalEmail.h
-C  选项是只生成客户端的Q默认是生成客户端和服务器端的,如果你在E序中用了vectorq要加上 –limport选项?br />卛_以生存客L存根E序和框架了?br />soapClient.cppQ编译客L的需要的存根例程?br />soapC.cppQsoapH.h:用来序列化和反序列化c/c++不同数据cd?br />soapServer.cpp: ~译服务器端的需要的存根例程?br />soapXXXProxy.h: 生成的代理类的头文g,使用代理cL需要此文g?br />本程序ؓsoapSendEmailBindingProxy.h?br />
W三步,是在vc中徏个工E,讄如下Q?br />在vc6中徏立工E,其源文g为:sendMailClient.cpp soapC.cpp
                                    soapClient.cpp   stdsoap2.cpp
头文件ؓQ?    AbysalEmail.h soapH.h soapStub.h stdsoap2.h      
其他依赖文g为:basetsd.h  sendemailbinding.nsmp
stdsoap2.cpp stdsoap2.h是下载的gSOAP中包含的?br />另外在所需要的库中把wsock32.lib加上QgSOAP也是采用socket方式q接的?br />其中sendMailClient.cpp为我写的客户端程序,E序如下Q?br />
#include "soapH.h"                          // 得到存根E序
#include "SendEmailBinding.nsmap"            //得到名称I间映射?br />#include <iostream>
#include  <string>
#include "soapSendEmailBindingProxy.h"

using namespace std;

int main(int argc, char **argv)
{
        struct soap email_soap;
        int result = -1;
   SendEmailBinding  EmailBind;              //生成代理cd?br />    _ns1__SendEmail  sendEmail;              //web服务发送电子邮件对?br />   _ns1__SendEmailResponse  Email_Response;  //web 服务q回发送结果对?br />   string from = "mseaspring";
   string to   = "David";
   string sub = "Hello test!";
   sendEmail.From = &from;
   sendEmail.FromAddress = "
mseaspring@hotmail.com ";
   sendEmail.MsgBody = "I want to test a web service!";
   sendEmail.To = &to;
   sendEmail.ToAddress = "
mseaspring@gmail.com ";
   sendEmail.Subject = ?br />
        result = EmailBind.__ns1__SendEmail(&sendEmail,  &Email_Response);
        if (result != 0)
        {
                printf("soap error ,errcode = %d\n", result);
        }
        else
        {
            cout<<"The result is :"<<Email_Response.ReturnCode<<endl;
                cout<<"恭喜你,邮g发送成功!"<<endl;
        }
        return 0;
}我程序中是采用代理类的方式编写的E序Q不用代理类的代码如下:
#include "soapH.h"                          //  得到存根E序
#include "SendEmailBinding.nsmap"            // 得到名称I间映射?br />#include <iostream>
#include  <string>
using namespace std;

int main(int argc, char **argv)
{
        struct soap email_soap;
        //初始化gSoapq行时环境变量,只需初始化一?br />        soap_init(&email_soap);
        int result = -1;
        //q程web服务的endpoint URL
   const char* server="http://www.abysal.com/soap/soapmail.wdtp";
   string from = "mseaspring";
   string to   = "David";
   string sub = "Hello test!";
   sendEmail.From = &from;
   sendEmail.FromAddress = "
mseaspring@hotmail.com ";
   sendEmail.MsgBody = "I want to test a web service!";
   sendEmail.To = &to;
   sendEmail.ToAddress = "
mseaspring@gmail.com ";
   sendEmail.Subject = ?br />    //调用Ҏq程服务产生函数的接?br />result = soap_call___ns1__SendEmail(&email_soap, server, "", &sendEmail,  &Email_Response);
        if(email_soap.error)
        {
                //在stderr中打印soap的错误信?br />                soap_print_fault(&email_soap,stderr);
                result = email_soap.error;
        }
    soap_destroy(&email_soap);// 删除反序列化cȝ实例,仅用于c++
        soap_end(&email_soap);    // 清空已经q行化的数据
        soap_done(&email_soap);   // 与gSOAP 环境相分?关闭q接
        if (result != 0)
        {
                printf("soap error ,errcode = %d\n", result);
        }
        else
        {
            cout<<"The result is :"<<Email_Response.ReturnCode<<endl;
                cout<<"恭喜你,邮g发送成功!"<<endl;
        }
        return 0;
}
你可能会问我怎么知道q程服务的接口阿Q?到soapStub.h中去扑ְ可以了,至于代理cȝ使用Q到代理cd文g中一看便知?br />好了Q终于要写完了,当然我们不仅可以~写客户端也可以~写服务器端E序Q至于服务器端,有兴的可以自己看看gSOAP里面的文档,也很单的Q不q也要花Ҏ间学习的了,呵呵?br />如果对于上面E序Q有谁没调试成功联系我,邮箱都写在程序里那。呵c?/font>

夜沁 2006-09-20 16:21 发表评论
]]>
SOAP协议规范http://www.shnenglu.com/yeqing/articles/12759.html夜沁夜沁Wed, 20 Sep 2006 07:15:00 GMThttp://www.shnenglu.com/yeqing/articles/12759.htmlhttp://www.shnenglu.com/yeqing/comments/12759.htmlhttp://www.shnenglu.com/yeqing/articles/12759.html#Feedback0http://www.shnenglu.com/yeqing/comments/commentRss/12759.htmlhttp://www.shnenglu.com/yeqing/services/trackbacks/12759.html阅读全文

夜沁 2006-09-20 15:15 发表评论
]]>
99ξþþŷƷվ| 91þþþþþ| պƷþһ| þþþþþþþ| һaƬþëƬ| þþþþþþ| ҹƷþþþþþ| þõӰ| ޾ƷþþþAV鶹| ղƷþþþþþ| Ʒѿþþ㽶| þˬ˸߳AV| ĻþþƷˮ | 㽶þþþþúݺɫ| þպƷһ| ˾þô߽槼| һɫþ88ۺպƷ| 69þþƷһ| ݺݾƷþþĻ| Ʒ˾þþ| 99þþù| ŷ޹Ʒþø| Ӱһþþþó˾Ʒۺ| ഺþ| þþƷһ| ԴӰȷþԴ| ͵͵þþþվ| ٸþþþþñŪ߳| Ʒһþ| Ʒþþþþ֣ݹ˾ | ۺϾƷ㽶þ| ŷþþҹһĻ | ҹAVëƬþ| 91Ʒɫ۾þ| þۺ˿ձ| ӰԺ˾þ| 91þùۺϾƷ| Ʒþþþþþ| 볬鱬Ļþ| պ뾫Ʒþһ| ޹þþþƷ|