概要:

          眼下ONVIF协议家族设备已占领数字监控行业半壁江山以上。亲,作为开发人员的你还在犹豫是否了解下吗?本文介绍了ONVIFclient从设备搜索,鉴权,能力获取,媒体信息获取,URI地址获取的整套流程。文章仅仅讲述了比較重要或其它博文没有讲述的开发点,具体能够參考文末參考文章。最后,能获得rtsp地址之后。然后去做其它功能比方录像,ptz这些就很得心应手了。本文出自CSDN-固本培元 ,转载注明出自:leolupy@gmail.com。


前言及鸣谢:

感谢guog先生。快活林高先生,onvif全国交流群的的酷夏先生在开发过程中给予的巨大支持,没有你们的帮助开发过程将异常艰难啊。谢谢了!

ONVIF介绍:

       ONVIF致力于通过全球性的开放接口标准来推进网络视频在安防市场的应用,这一接口标准将确保不同厂商生产的网络视频产品具有互通性。2008年11月。论坛正式公布了ONVIF第一版规范——ONVIF核心规范1.0。随着视频监控的网络化应用,产业链的分工将越来越细。

有些厂商专门做摄像头。有些厂商专门做DVS。有些厂商则可能专门做平台等,然后通过集成商进行集成,提供给终于客户。这样的产业合作模式,已经迫切的须要行业提供越来越标准化的接口平台。


流程总览:

本文开发环境:Centos6.4  Gsoap:2.8.16  soap:1.2 onvif:2.4 。 注: 本文提供的參考代码事实上网上都能够找到,这里做一个整理。供大家交流学习,共同提高。


搜索:Probe: 发现网络摄像头。获取webserver地址

http://192.168.15.240/onvif/device_service

能力获取:GetCapabilities:获取设备能力文件。从中识别出媒体信息地址URI:  http://192.168.15.240/onvif/Media

媒体信息获取:GetProfiles: 获取媒体信息文件。识别主通道、子通道的视频编码分辨率

RTSP地址获取:GetStreamUri:获取指定通道的流媒体地址  rtsp://192.168.15.240:554/Streaming/Channels/2?

transportmode=unicast

Gsoap及开发框架生成:


2.安装:  ./configure && make && make install
            期间可能会有一些报错,自己解决哦。
3.离线或者在线生成onvif.h。假设不须要最新的版本号推荐离线方式。

笔者使用的是这样的方式。

     离线文件下载地址:感谢guog先生的共享:

命令:

wsdl2h -o onvif.h -c -s -t ./typemap.dat devicemgmt.wsdl media.wsdl event.wsdl display.wsdl deviceio.wsdl imaging.wsdl ptz.wsdl receiver.wsdl recording.wsdl search.wsdl remotediscovery.wsdl replay.wsdl analytics.wsdl analyticsdevice.wsdl actionengine.wsdl accesscontrol.wsdl doorcontrol.wsdl 

离线文件在:

http://download.csdn.net/detail/u011597695/5875143


    在线命令:
wsdl2h -o onvif.h -c -s -t ./typemap.dat http://www.onvif.org/onvif/ver10/device/wsdl/devicemgmt.wsdl http://www.onvif.org/onvif/ver10/media/wsdl/media.wsdl http://www.onvif.org/onvif/ver10/event/wsdl/event.wsdl http://www.onvif.org/onvif/ver10/display.wsdl http://www.onvif.org/onvif/ver10/deviceio.wsdl http://www.onvif.org/onvif/ver20/imaging/wsdl/imaging.wsdl http://www.onvif.org/onvif/ver20/ptz/wsdl/ptz.wsdl http://www.onvif.org/onvif/ver10/receiver.wsdl  http://www.onvif.org/onvif/ver10/recording.wsdl http://www.onvif.org/onvif/ver10/search.wsdl http://www.onvif.org/onvif/ver10/network/wsdl/remotediscovery.wsdl http://www.onvif.org/onvif/ver10/replay.wsdl http://www.onvif.org/onvif/ver20/analytics/wsdl/analytics.wsdl http://www.onvif.org/onvif/ver10/analyticsdevice.wsdl http://www.onvif.org/ver10/actionengine.wsdl http://www.onvif.org/ver10/pacs/accesscontrol.wsdl http://www.onvif.org/ver10/pacs/doorcontrol.wsdl 

(记得拷贝gsoap的typemap文件至生成文件夹下,wsdl2h命令须要这个。


     离线命令:
wsdl2h -o onvif.h -c -s -t ./typemap.dat devicemgmt.wsdl media.wsdl event.wsdl display.wsdl deviceio.wsdl imaging.wsdl ptz.wsdl receiver.wsdl recording.wsdl search.wsdl remotediscovery.wsdl replay.wsdl analytics.wsdl analyticsdevice.wsdl actionengine.wsdl accesscontrol.wsdl doorcontrol.wsdl 

如今能够開始生成了:例如以下:

假设直接生成相应C的库文件会发生反复定义错误。能够改动该文件。

wsa5.h(288): **ERROR**: remote method name clash: struct/class 'SOAP_ENV__Fault' already declared at line 274

打开文件gsoap_2.8.16/gsoap-2.8/gsoap/import/ wsa5.h

将277行int SOAP_ENV__Fault改动为int SOAP_ENV__Fault_alex

笔者没有使用这样的方法,是将这个结构体直接凝视的方式。最后的结果是,都能够使用。

同一时候上一步生成的onvif.h文件里没有打开wsse.h。 导致最后生成代码中SOAP_ENV__Header 结构体中缺少定义 wsse__Security数据段,无法进行鉴权命令。

即:加入对openssl的支持,在上一步生成的onvif.h中加入(可选)

  1. #import "wsse.h"

随后使用命令生成:

soapcpp2  -c onvif.h -x -I/root/Tools/Gsoap/gsoap-2.8/gsoap/import -I/root/Tools/Gsoap/gsoap-2.8/gsoap/ -I/root/Tools/Gsoap/gsoap-2.8/gsoap/custom -I/root/Tools/Gsoap/gsoap-2.8/gsoap/extras -I/root/Tools/Gsoap/gsoap-2.8/gsoap/plugin 

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ3ViZW5wZWl5dWFu/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">



到此为止,基于 C 的client和server的Onvif开发框架及已经搭建完毕。


设备搜索原理及编程技巧:

        搜索发现的基本原理是:设备上server监听239.255.255.250的3702port。所以,假设要实现跨网段搜索onvif设备须要路由的支持。

仅仅要组播数据包能收到,设备就能被搜到。

原理是这样。

參考代码:


struct soap* NewSoap(struct SOAP_ENV__Header *header,struct soap* soap,
wsdd__ProbeType *req_,
wsdd__ScopesType *sScope_)
{
soap = soap_new();
if(NULL == soap )
{
printf("sopa new error\r\n");
return NULL;
} soap->recv_timeout = 5;
soap_set_namespaces(soap, namespaces); soap_default_SOAP_ENV__Header(soap, header); uuid_t uuid;
char guid_string[100];
uuid_generate(uuid);
uuid_unparse(uuid, guid_string); header->wsa__MessageID = guid_string;
header->wsa__To = "urn:schemas-xmlsoap-org:ws:2005:04:discovery";
header->wsa__Action = "http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe";
soap->header = header; soap_default_wsdd__ScopesType(soap, sScope_);
sScope_->__item = "";
soap_default_wsdd__ProbeType(soap, req_);
req_->Scopes = sScope_;
req_->Types = ""; //"dn:NetworkVideoTransmitter"; return soap ;
}
int i = 0;
result = soap_send___wsdd__Probe(soap, MULTICAST_ADDRESS, NULL, &req); while(result == SOAP_OK)
{
result = soap_recv___wsdd__ProbeMatches(soap, &resp);
if(result == SOAP_OK)
{
if(soap->error)
{
printf("soap error 1: %d, %s, %s\n", soap->error, *soap_faultcode(soap), *soap_faultstring(soap));
result = soap->error;
}
else
{
printf("Onvif Device detected *********************************************\r\n");
for(i = 0; i < resp.wsdd__ProbeMatches->__sizeProbeMatch; i++)
{
printf("__sizeProbeMatch : %d\r\n", resp.wsdd__ProbeMatches->__sizeProbeMatch);
printf("wsa__EndpointReference : %p\r\n", resp.wsdd__ProbeMatches->ProbeMatch->wsa__EndpointReference);
printf("Target EP Address : %s\r\n", resp.wsdd__ProbeMatches->ProbeMatch->wsa__EndpointReference.Address);
printf("Target Type : %s\r\n", resp.wsdd__ProbeMatches->ProbeMatch->Types);
printf("Target Service Address : %s\r\n", resp.wsdd__ProbeMatches->ProbeMatch->XAddrs);
printf("Target Metadata Version : %d\r\n", resp.wsdd__ProbeMatches->ProbeMatch->MetadataVersion);
if(resp.wsdd__ProbeMatches->ProbeMatch->Scopes)
{
printf("Target Scopes Address : %s\r\n", resp.wsdd__ProbeMatches->ProbeMatch->Scopes->__item);
}
}
break;
}
}
else if (soap->error)
{
printf("[%d] soap error 2: %d, %s, %s\n", __LINE__, soap->error, *soap_faultcode(soap), *soap_faultstring(soap));
result = soap->error;
}
}

        注:搜索到的设备能够增加到自己的设备管理中。这里就不做过多的说明了。


设备鉴权:

         鉴权的实现能够非常easy也能够非常难,这里笔者使用的是gsoap提供的方法:直接调用就可以:

soap_wsse_add_UsernameTokenDigest(soap,"user", ONVIF_USER, ONVIF_PASSWORD);

原理也非常easy明确事实上,就是讲http的soap消息增加相应header中xml的元素而已。然后敏感消息digest MD5加密编码。

         所以编译过程中须要使用 lcrypto 也就非常正常了。

获取能力:

         soap 的http消息通信。參考代码:

void UserGetCapabilities(struct soap *soap	,struct __wsdd__ProbeMatches *resp,
struct _tds__GetCapabilities *capa_req,struct _tds__GetCapabilitiesResponse *capa_resp)
{
capa_req->Category = (enum tt__CapabilityCategory *)soap_malloc(soap, sizeof(int));
capa_req->__sizeCategory = 1;
*(capa_req->Category) = (enum tt__CapabilityCategory)(tt__CapabilityCategory__Media); capa_resp->Capabilities = (struct tt__Capabilities*)soap_malloc(soap,sizeof(struct tt__Capabilities)) ; soap_wsse_add_UsernameTokenDigest(soap,"user", ONVIF_USER, ONVIF_PASSWORD);
printf("\n--------------------Now Gettting Capabilities NOW --------------------\n\n"); int result = soap_call___tds__GetCapabilities(soap, resp->wsdd__ProbeMatches->ProbeMatch->XAddrs, NULL, capa_req, capa_resp); if (soap->error)
{
printf("[%s][%d]--->>> soap error: %d, %s, %s\n", __func__, __LINE__, soap->error, *soap_faultcode(soap), *soap_faultstring(soap));
int retval = soap->error;
exit(-1) ;
}
else
{
printf(" \n--------------------GetCapabilities OK! result=%d--------------\n \n",result);
if(capa_resp->Capabilities==NULL)
{
printf(" GetCapabilities failed! result=%d \n",result);
}
else
{ printf(" Media->XAddr=%s \n", capa_resp->Capabilities->Media->XAddr);
}
}
}

获取媒体信息Profile:

         soap 的http消息通信。參考代码:
void UserGetProfiles(struct soap *soap,struct _trt__GetProfiles *trt__GetProfiles,
struct _trt__GetProfilesResponse *trt__GetProfilesResponse ,struct _tds__GetCapabilitiesResponse *capa_resp)
{
int result=0 ; printf("\n-------------------Getting Onvif Devices Profiles--------------\n\n");
soap_wsse_add_UsernameTokenDigest(soap,"user", ONVIF_USER, ONVIF_PASSWORD);
result = soap_call___trt__GetProfiles(soap, capa_resp->Capabilities->Media->XAddr, NULL, trt__GetProfiles, trt__GetProfilesResponse);
if (result==-1)
//NOTE: it may be regular if result isn't SOAP_OK.Because some attributes aren't supported by server.
//any question email leoluopy@gmail.com
{
printf("soap error: %d, %s, %s\n", soap->error, *soap_faultcode(soap), *soap_faultstring(soap));
result = soap->error;
exit(-1);
}
else{
printf("\n-------------------Profiles Get OK--------------\n\n");
if(trt__GetProfilesResponse->Profiles!=NULL)
{
if(trt__GetProfilesResponse->Profiles->Name!=NULL){
printf("Profiles Name:%s \n",trt__GetProfilesResponse->Profiles->Name); }
if(trt__GetProfilesResponse->Profiles->token!=NULL){
printf("Profiles Taken:%s\n",trt__GetProfilesResponse->Profiles->token);
}
}
else{
printf("Profiles Get inner Error\n"); }
}
printf("Profiles Get Procedure over\n"); }

获取RTSP的URI:

         soap 的http消息通信。參考代码:

void UserGetUri(struct soap *soap,struct _trt__GetStreamUri *trt__GetStreamUri,struct _trt__GetStreamUriResponse *trt__GetStreamUriResponse,
struct _trt__GetProfilesResponse *trt__GetProfilesResponse,struct _tds__GetCapabilitiesResponse *capa_resp)
{
int result=0 ;
trt__GetStreamUri->StreamSetup = (struct tt__StreamSetup*)soap_malloc(soap,sizeof(struct tt__StreamSetup));//初始化,分配空间
trt__GetStreamUri->StreamSetup->Stream = 0;//stream type trt__GetStreamUri->StreamSetup->Transport = (struct tt__Transport *)soap_malloc(soap, sizeof(struct tt__Transport));//初始化,分配空间
trt__GetStreamUri->StreamSetup->Transport->Protocol = 0;
trt__GetStreamUri->StreamSetup->Transport->Tunnel = 0;
trt__GetStreamUri->StreamSetup->__size = 1;
trt__GetStreamUri->StreamSetup->__any = NULL;
trt__GetStreamUri->StreamSetup->__anyAttribute =NULL; trt__GetStreamUri->ProfileToken = trt__GetProfilesResponse->Profiles->token ; printf("\n\n---------------Getting Uri----------------\n\n"); soap_wsse_add_UsernameTokenDigest(soap,"user", ONVIF_USER, ONVIF_PASSWORD);
soap_call___trt__GetStreamUri(soap, capa_resp->Capabilities->Media->XAddr, NULL, trt__GetStreamUri, trt__GetStreamUriResponse); if (soap->error) {
printf("soap error: %d, %s, %s\n", soap->error, *soap_faultcode(soap), *soap_faultstring(soap));
result = soap->error; }
else{
printf("!!!!NOTE: RTSP Addr Get Done is :%s \n",trt__GetStreamUriResponse->MediaUri->Uri);
}
}

最后贴一个终端截图:





开发注意事项:(必读)

soap通信的命名空间假设错误则不能检索到设备:编译好的wsdd.nsmap文件须要改动命名空间,例如以下:

假设要正常开发,被检索到,或者发现其它设备须要nsmap改动例如以下:1.1换1.2

下面命名空间表示SOAP1.1版本号:

{"SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/", "http://www.w3.org/*/soap-envelope", NULL},

{"SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/", "http://www.w3.org/*/soap-encoding", NULL}, //1.1

下面命名空间表示SOAP1.2版本号:

{"SOAP-ENV", "http://www.w3.org/2003/05/soap-envelope", "http://schemas.xmlsoap.org/soap/envelope/", NULL},

{"SOAP-ENC", "http://www.w3.org/2003/05/soap-encoding", "http://schemas.xmlsoap.org/soap/encoding/", NULL},  //1.2

另外存在的client搜索不到设备情况:

1.是否有vpn,存在的话。本机IP会产生变化导致不能搜到?抓包能够看到,3702port包的数据源地址改变。

2.uuid是否已经赋值。

3.有时,windows宿主机装有虚拟机,也可能造成onvifclient的ip获取错误。

故搜索不到。

这些问题。在交换机或者路由支持本地局域网跨网段数据UDP交互时,均不会产生。

调试技巧:

fsend/ frecv 打印出发送和接收到的报文。使用xml编辑器分析。

当然也能够直接用浏览器看。

1、打开onvif调试开关,以便让onvif打印一些可用的调试信息。

在Makefile中加入调试宏定义如: CC = gcc -DDEBUG

2、打开调试宏后。默认在程序执行的文件夹产生三个文件:

RECV.log

SENT.log

TEST.log

RECV.log是onvif接收到的SOAP数据,没接收一条。都会在RECV.log中记录

SENT.log是onvif发送出去的SOAP数据。没发送一套,也会在SENT.log中生成记录

最后是TEST.log,假设说RECV和SENT能够用wireshark工具抓包取代。那么TEST.log是谁也替代不了的,TEST.log记录了onvif的实时的工作状态。

尤其当出现segmentation fault错误。TEST.log就成了唯一一个可以定位到详细内存出错的地方了。

SOAP_TYPE返回soap->error=4的错误说明

关于数据正确(抓包可收到数据)。但soap返回错误,为4 及 SOAP_TYPE 的问题:

GetCapabilities的过程错误时。

多次调试后得出结论,是tt__CapabilityCategory 的设置问题,有的设备不具备所有功能,而请求所有或请求没有的功能就可能造成这样的问题,推荐写5(tt__CapabilityCategory__Media)  这是大多数设置有的能力。并且最经常使用。

GetProfile时错误:

事实上数据在抓包过程中也能全然抓到,多次调试后。发现结构体须要的Name以及tokenkeyword被赋值。

其它的没有,说明本点返回与server的支持性有非常大关系。及。开发过程中须要相应自己的需求,依据实际的须要和返回错误,读取返回结构体数据。

资源:

ONVIFDEVICEMANAGER下载地址:

http://pan.baidu.com/share/link?

shareid=1967805400&uk=70662920&fid=3981296515

ONVIFTESTTOOL下载地址:

http://www.cr173.com/soft/66448.html

官网开发人员向导资料下载地址:

http://www.onvif.org/Resources/WhitePapers.aspx

參考文章:

onvif规范的实现:使用gSOAP创建SOAP调用实例

http://blog.csdn.net/ghostyu/article/details/8162280

Onvif开发之服务端成功对接Rtsp视频流篇

http://blog.csdn.net/max_min_go/article/details/17964643

linux设备上的Onvif 实现10:获取支持通道的RTSP地址

http://gaohtao.blog.163.com/blog/static/58241823201381113214599/

Onvif开发之client鉴权获取參数篇

http://blog.csdn.net/max_min_go/article/details/17617057

ONVIF协议开发资源

http://www.csdn.net/tag/onvif%252520%2525E5%25258D%25258F%2525E8%2525AE%2525AE

onvif开发之设备发现功能的实现

http://blog.csdn.net/love_xjhu/article/details/11821037

Linux设备上的Onvif实现16:实现Onvif鉴权

http://blog.csdn.net/u012084827/article/details/19031969

Onvif开发之Linux下gsoap的使用及移植

http://blog.csdn.net/love_xjhu/article/details/9772361

onvif开发总结

http://blog.csdn.net/zsl461975543/article/details/8971143

代码框架生成之Onvif开发

http://www.yc-edu.org/C__peixun/6655.html

linux设备上的Onvif 实现4:成功编译gsoap 2.8.15

http://blog.csdn.net/u012084827/article/details/12202133

onvif规范的实现:onvif开发经常使用调试方法 和常见的segmentation
fault错误

http://blog.csdn.net/ghostyu/article/details/8432760

linux设备上的Onvif 实现6:获取摄像头的流媒体地址完整流程

http://blog.csdn.net/u012084827/article/details/12201997

S​O​A​P​ ​错​误​代​码​表

http://wenku.baidu.com/link?url=rujSmnpjBxjS3mGZrejoVVOShcPu_5Wu_9RKrQ6qWCB12xrZUvVoFkYRepLu0y6oTk6-bB5AnJ_7KxF6s8rXcb1BFko6DbBpXg0_7G0D7cu

linux设备上的Onvif 实现8:编写媒体信息获取程序

http://blog.csdn.net/u012084827/article/details/12201897


ONVIFclient搜索设备获取rtsp地址开发笔记(精华篇)的更多相关文章

  1. ONVIF客户端搜索设备获取rtsp地址开发笔记(精华篇)

    原文  http://blog.csdn.net/gubenpeiyuan/article/details/25618177   概要: 目前ONVIF协议家族设备已占据数字监控行业半壁江山以上,亲, ...

  2. 【视频开发】ONVIF客户端搜索设备获取rtsp地址开发笔记(精华篇)

    转载地址:http://blog.csdn.net/gubenpeiyuan/article/details/25618177 概要:           目前ONVIF协议家族设备已占据数字监控行业 ...

  3. ONVIFclient搜索设备获取rtsp解决开发笔记(精华文章)

    总结:           眼下ONVIF协议系列设备已经超过一半的数字监控行业占据更多,关闭,作为一个开发者,你还在犹豫下就明白了?本文介绍了ONVIFclient从搜索,认证,获取,媒体信息获取. ...

  4. Atitit onvif协议获取rtsp地址播放java语言 attilx总结

    Atitit onvif协议获取rtsp地址播放java语言 attilx总结 1.1. 获取rtsp地址的算法与流程1 1.2. Onvif摄像头的发现,ws的发现机制,使用xcf类库1 2. 调用 ...

  5. iOS7以下设备获取mac地址

    注意,是iOS7以下的设备,直接上源码,获取mac地址都是为了唯一标识一个设备的,但iOS7设备的mac地址为 020000000000 MacAddress.h #include <sys/s ...

  6. 【android】开发笔记---存储篇

    SQLite批量插入数据 当我们执行 db.execSQL("sql语句")的时候,系统进行了一次IO操作,当批量插入成千上万条时,就会消耗掉许多资源. 解决之道是通过事务,统一提 ...

  7. EasyNVR网页摄像机无插件H5、谷歌Chrome直播方案-Onvif(二)使用Onvif协议进行设备RTSP地址获取

    背景介绍 EasyNVR最大的优势就是兼容性,通过RTSP协议接入传统网络摄像机.NVR.编码器等,使用RTSP协议接入能兼容市面上绝大多数网络摄像机等源设备,最大程度的提高整体方案的硬件设备的兼容性 ...

  8. 通过Onvif设备探索获取EasyNVR网页无插件播放所需要的摄像机硬盘录像机NVR的RTSP地址

    想实现网络监控摄像头进行视频直播的朋友门应该知道,方法其实非常简单,你不需要使用支持直播的网络摄像机,只需要经过一套流媒体服务器将监控摄像头的RTSP视频流转为RTMP\HLS\HTTP-FLV视频流 ...

  9. Linux下onvif客户端获取h265 IPC摄像头的RTSP地址

    1. 设备搜索,去获取webserver 的地址 ,目的是在获取能力提供服务地址,demo:https://www.cnblogs.com/croxd/p/10683429.html 2. GetCa ...

随机推荐

  1. linux octave 4.0安装

    octave,linux下的安装.官网:Octive,请参考以下资料: 安装教程:Ubuntu通过源码编译安装Octave 4.0

  2. Linux 内核编译步骤及配置详解

    前言    Linux内核是操作系统的核心,也是操作系统最基本的部分. Linux内核的体积结构是单内核的.但是他充分采用了微内核的设计思想.使得虽然是单内核.但工作在模块化的方式下.并且这个模块可以 ...

  3. Git_使用GitHub

    我们一直用GitHub作为免费的远程仓库,如果是个人的开源项目,放到GitHub上是完全没有问题的.其实GitHub还是一个开源协作社区,通过GitHub,既可以让别人参与你的开源项目,也可以参与别人 ...

  4. 给Android组件添加事件一个很好用的方法

    在这里想和大家分享一下很好用的添加事件方法,特别是在处理ListView里的Item事件的时候,很方便. 首先,在XML里布局的时候,添加这样一个属性: android:onClick="C ...

  5. Visual Studio中Debug和Release的区别

    在Visual Studio中,生成应用程序的时候有2种模式:Debug和Release.两者之间如何取舍呢? 假设有这么简单的一段代码,在主程序中调用方法M1,M1方法调用M2方法,M2方法调用M3 ...

  6. CMMI5级——原因分析及解决方案(Causal Analysis and Resolution)

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/u010825142/article/details/15338085 聪明的人在出现问题的时候,除了 ...

  7. python测试开发django-6.模板中include使用

    前言 当我们打开一个网站的时候,在打开不同的页面时候,会发现每个页面的顶部.底部内容都差不多,这样就可以把这些公共的部分,单独抽出来. 类似于python里面的函数,把公共部分写成函数,然后调用就行了 ...

  8. Windows Server 2003 R2 IIS服务的命令行方式重启命令

    iisreset /RESTART 停止后启动   iisreset /START 启动IIS (如果停止)   iisreset /STOP 停止IIS (如果启动)   iisreset /REB ...

  9. Android之获取sdcard卡的信息

    public static SDCardInfo getSDCardInfo() { String sDcString = android.os.Environment.getExternalStor ...

  10. 【视频分享】Liger UI实战集智建筑project管理系统配商业代码(打印报表、角色式权限管理)

    QQ 2059055336 课程讲师:集思博智 课程分类:.net 适合人群:中级 课时数量:23课时 用到技术:Liger UI框架.AJAX.JSON数据格式的序列化与反序列化.角色的交叉权限管理 ...