<2024年12月>
24252627282930
1234567
891011121314
15161718192021
22232425262728
2930311234

统计

  • 随笔 - 21
  • 文章 - 0
  • 评论 - 2
  • 引用 - 0

常用链接

留言簿

随笔档案

搜索

  •  

最新评论

阅读排行榜

评论排行榜

置顶随笔

[置顶]师傅带徒弟 但是不能 教会徒弟饿死师傅!

     摘要:   分享到 QQ空间新浪微博腾讯微博人人网开心网搜狐微博查看更多(110) JiaThis 分享到各大网站 复制网址收藏夹打印邮件QQ空间新浪微博腾讯微博搜狐微博网易微博人人网开心网搜狐白社会淘江湖豆瓣腾讯朋友猫扑推客百度搜藏百度贴吧天涯社区凤凰微博饭否飞信优士网51社区...  阅读全文

posted @ 2011-08-16 10:52 FengRalf 阅读(495) | 评论 (0)编辑 收藏

2011年8月16日

师傅带徒弟 但是不能 教会徒弟饿死师傅!

     摘要:   分享到 QQ空间新浪微博腾讯微博人人网开心网搜狐微博查看更多(110) JiaThis 分享到各大网站 复制网址收藏夹打印邮件QQ空间新浪微博腾讯微博搜狐微博网易微博人人网开心网搜狐白社会淘江湖豆瓣腾讯朋友猫扑推客百度搜藏百度贴吧天涯社区凤凰微博饭否飞信优士网51社区...  阅读全文

posted @ 2011-08-16 10:52 FengRalf 阅读(495) | 评论 (0)编辑 收藏
程序员如何保护自己的那点东西

     摘要:   分享到 QQ空间新浪微博腾讯微博人人网开心网搜狐微博查看更多(110) JiaThis 分享到各大网站 复制网址收藏夹打印邮件QQ空间新浪微博腾讯微博搜狐微博网易微博人人网开心网搜狐白社会淘江湖豆瓣腾讯朋友猫扑推客百度搜藏百度贴吧天涯社区凤凰微博饭否飞信优士网51社区...  阅读全文

posted @ 2011-08-16 10:50 FengRalf 阅读(377) | 评论 (0)编辑 收藏
[导入]C的位域简介

感觉很少有资料详细地讲结构体,所以今天来这里请教大家几个关于结构体的问题,是C语言,纯C,不是C++。
1、结构体成员是否可以有默认值?
C语言中是否可以在定义结构体的时候就指定其成员的默认值,就像C++中函数可以为其参数指定默认值那样。比如

C/C++ code
typedef struct _test
{
    int a=5;//这句肯定不对
    ...
}test;
//然后我再这样定义
test inst;//即使我不对inst进行其他操作,inst.a也直接等于5,而不是一个随机值

当然上这段代码肯定是错的,我是想问结构体有没有实现这种功能的方法,像test inst={5,...};这种方法就不考虑了,这是结构体变量初始化,而不是在定义结构体时指定默认值。
2、结构体成员最大值的问题。
这是我最近看别人的代码时看到了,好不容易才勉强弄明白了是什么意思,示例代码如下:
C/C++ code
typedef struct _test
{
    int a:N;
    ...
}test;
这样一来虽然a是int型,但是其最大值只能是2的N次方减1(2^N-1)。到目前为止,我仅仅知道这一点,但是不明白编译器(或者说程序,应该是编译器吧)是如何来保证它的值被限定在这个范围内的。也请大家给一些这方面的资料。
3、结构体的继承与成员函数
姑且叫作“继承”和“成员函数”吧,因为我也不知道具体应该叫什么,感觉继承和成员函数应该是C++中面向对象的说法了,不知道C的结构体中是不是也有这些东西,或者说这是C++对C是扩展?请看
http://topic.csdn.net/t/20050713/18/4142554.html,在这个页面中也这样两段代码:
C/C++ code
//Code1
struct TEMP    
{    
    int   x;    
    int   y;    
    TEMP(int   x=0,int   y=0):x(x),y(y){}//结构体也可以有成员函数?
};

//Code2
struct TEMP_Wrapper:TEMP//结构体也可以继承?
{  
    TEMP_Wrapper(int xx,int yy)  
    {x=xx;y=yy;}  
};

对于这些代码我实在看不明白,从来没见过这样的用法和相关资料,还请大家指点一二,给点资料最好。

1 结构体,从汇编上理解就是一块指定大小内存空间的数据

没见过 c 语言结构体有默认值的

2 位域

3 这是 C++ 语法

 
有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。
例如在存放一个开关量时,只有0和1 两种状态,用一位二进位即可。为了节省存储空间,
并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”
是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个
域名,允许在程序中按域名进行操作。 这样就可以把几个不同的对象用一个字节的二进
制位域来表示。
一、位域的定义和位域变量的说明位域定义与结构定义相仿,其形式为: 
        struct 位域结构名 
        { 位域列表 };
其中位域列表的形式为: 类型说明符 位域名:位域长度 
例如: 
struct bs
{
        int a:8;
        int b:2;
        int c:6;
};
位域变量的说明与结构变量说明的方式相同。 可采用先定义后说明,同时定义说明或者
直接说明这三种方式。例如: 
struct bs
{
        int a:8;
        int b:2;
        int c:6;
}data;
说明data为bs变量,共占两个字节。其中位域a占8位,位域b占2位,位域c占6位。对于位
域的定义尚有以下几点说明:
       1. 一个位域必须存储在同一个字节中,不能跨两个字节。如一个字节所剩空间不
够存放另一位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。
例如: 
struct bs
{
        unsigned a:4
        unsigned :0 /*空域*/
        unsigned b:4 /*从下一单元开始存放*/
        unsigned c:4
}
在这个位域定义中,a占第一字节的4位,后4位填0表示不使用,b从第二字节开始,占用
4位,c占用4位。
        2. 由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也
就是说不能超过8位二进位。
        3. 位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使
用的。例如: 
struct k
{
        int a:1
        int :2 /*该2位不能使用*/
        int b:3
        int c:2
};
从以上分析可以看出,位域在本质上就是一种结构类型, 不过其成员是按二进位分配的。
二、位域的使用位域的使用和结构成员的使用相同,其一般形式为: 
        位域变量名·位域名 
位域允许用各种格式输出。
main(){
        struct bs
        {
                unsigned a:1;
                unsigned b:3;
                unsigned c:4;
        } bit,*pbit;
        bit.a=1;
        bit.b=7;
        bit.c=15;
        printf("%d,%d,%d\n",bit.a,bit.b,bit.c);
        pbit=&bit;
        pbit->a=0;
        pbit->b&=3;
        pbit->c|=1;
        printf("%d,%d,%d\n",pbit->a,pbit->b,pbit->c);

上例程序中定义了位域结构bs,三个位域为a,b,c。说明了bs类型的变量bit和指向bs类型
的指针变量pbit。这表示位域也是可以使用指针的。
程序的9、10、11三行分别给三个位域赋值。( 应注意赋值不能超过该位域的允许范围)程
序第12行以整型量格式输出三个域的内容。第13行把位域变量bit的地址送给指针变量
pbit。第14行用指针方式给位域a重新赋值,赋为0。第15行使用了复合的位运算符"&=",
该行相当于:pbit->b=pbit->b&3位域b中原有值为7,与3作按位与运算的结果为3
(111&011=011,十进制值为3)。同样,程序第16行中使用了复合位运算"|=".之所以要有透析基础知识这么个分栏,就是告诉大家重在细节的道理,粗略的东西谁都懂,修炼内功为高手的必经之路.


文章来源:http://fengqing888.blog.163.com/blog/static/33011416201171610135460

posted @ 2011-08-16 10:14 FengRalf 阅读(475) | 评论 (0)编辑 收藏
[导入]RTMP协议

如控制信息、时间信息等),取决于具体的应用。找到这些基本的东西,再去看协议的时候,能够更好的抓住协议的主体进行分析和设计了。

    您的浏览器可能不支持显示此图像。         如图   协议物理结构


2 RTMP 协议概述

   RTMP 协议是被 Flash 用于对象、视频、音频的传输。该协议建立在 TCP 协议或者轮询 HTTP 协议之上, RTMP 协议就像一个用来装数据包的容器,这些数据可以是 AMF 格式的数据,也可以是 FLV 中的视 / 音频数据。一个单一的连接可以通过不同的通道传输多路网络流,这些通道中的包都是按照固定大小的包传输的 .


3 RTMP 协议部分
3.1 协议头

struct RTMP_HEAD

{

          char cChannelid : 6;// 第一个字节的后 6 位

          char cCheadsize ; // 第一个字节的头两位


      char cTimer[3];  // 三个字节表示的时间信息


      char cLength[3]; // 三个字节表示的长度


      char cDatatype; // 数据类型


      char sStreamid[4]; // 流标识


};


这里有三个最基本的元素(唯一标示 )、(类型 )和(净核的长度 )分别是: cChannelid 、 cDatatype 和 cLength 。


3.2 数据类型

数据类型 决定了协议上层可以做的具体的事情,和使用协议的人必须遵循的规则。

同时数据类型 说明了净核 的基本内容。

RTMP 数据类型:


0×01 Chunk Size changes the chunk size for packets
0×02 Unknown anyone know this one?
0×03 Bytes Read send every x bytes read by both sides
0×04 Ping ping is a stream control message, has subtypes
0×05 Server BW the servers downstream bw
0×06 Client BW the clients upstream bw
0×07 Unknown anyone know this one?
0×08 Audio Data packet containing audio
0×09 Video Data packet containing video data
0x0A - 0×11 Unknown anyone know?
0×12 Notify an invoke which does not expect a reply
0×13 Shared Object has subtypes
0×14 Invoke like remoting call, used for stream actions too.

3.3 协议的净核

   RTMP 的协议净核是用 AMF 格式来描述, AMF 格式本身的产生就是为了 RTMP 协议服务的,最初的 RTMP 采用 XML 的形式传输数据,但 XML 只是字符形式的值对的格式传输数据,而随着应用的普及这完全不能满足要求了,比如对象、结构、数组,甚至可以是数据集,配合 DataGrid 组件可以很方便地显示数据。 
为了处理复杂数据类型,采用一种独有的方式使 Flash 与应用服务器间可以来回传送数据势在必行。于是 AMF 应运而生。

AMF 是 Adobe 独家开发出来的通信协议,它采用二进制压缩,序列化、反序列化、传输数据,从而为 Flash 播放器与 Flash Remoting 网关通信提供了一种轻量级的、高效能的通信方式。如下图所示。 
您的浏览器可能不支持显示此图像。  
AMF 最大的特色在于可直接将 Flash 内置对象,例如 Object, Array, Date, XML ,传回服务器端,并且在服务器端自动进行解析成适当的对象,这就减轻了开发人员繁复工作,同时也更省了开发时间。由于 AMF 采用二进制编码,这种方式可以高度压缩数据,因此非常适合用 来传递大量的资料。数据量越大, Flash Remoting 的传输效能就越高,远远超过 Web Service 。至于 XML, LoadVars 和 loadVariables() ,它们使用纯文本的传输方式,效能就更不能与 Flash Remoting 相提并论了。 
注意: Flash Remoting 需要浏览器支持 Binary POST , Flash 播放器在 Netscape 6.x. 环境下运行 Flash Remoting 会不起作用( Flash Remoting 调用没有效果也不返回错误), Netscape 7 已经纠正了这个 bug 。对于早期 Safari 和 Chimera 版的苹果机也有这个问题。 
同样是轻量级数据交换协议,同样是通过调用远程服务,同样是基于标准的 HTTP 和 HTTPS 协议, Flash Remoting 为什么选择了使用 AMF 而放弃了 SOAP 与 Flash 播放器通信呢  有如下原因: 
 
SOAP 将数据处理成 XML 格式,相对于二进制的 AFM 太冗长了;  
AMF 能更有效序列化数据;因为 AMF 的初衷只是为了支持 Flash ActionScript 的数据类型,而 SOAP 却致力于提供更广泛的用途;  
AMF 支持 Flash 播放器 6 只需要浏览器增加 4 KB 左右(压缩后)的大小,而 SOAP 就大多了;  
SOAP 的一些头部文件请求在 Flash 播放器 6 不支持。那 Flash 播放器 6 为什么能访问基于 SOAP 的 Web 服务呢?原来 Flash Remoting 网关将 SOAP 请求在服务器端与转换成 AFM 格式,然后利用 AFM 与 Flash 播放器通信。另外, AMF 包中包含 onResult 事件(比如说 response 事件)和 onStatus 事件(比如说 error 事件),这些事件对象在 Flash 中可以直接使用。  
AMF 从 Flash MX 时代的 AMF0 发展到现在的 AMF3 。 AMF3 用作 Flash Playe 9 的 ActionScript 3.0 的默认序列化格式,而 AMF0 则用作旧版的 ActionScript 1.0 和 2.0 的序列化格式。 在网络传输数据方面, AMF3 比 AMF0 更有效率。 AMF3 能将 int 和 uint 对象作为整数( integer )传输,并且能序列化 ActionScript 3.0 才支持的数据类型 , 比如 ByteArray , XML 和 Iexternalizable 。

      AMF 很好的解决了内容的丰富性。(具体 AMF 格式参考附件格式文档)


3.3.1 AMF中的数据类型Data Types

AMF0 supports the following data types (with their type field values):


NUMBER = 0x00
BOOLEAN = 0x01
STRING = 0x02
OBJECT = 0x03
MOVIECLIP = 0x04
NULL_VALUE = 0x05
UNDEFINED = 0x06
REFERENCE = 0x07
ECMA_ARRAY = 0x08
OBJECT_END = 0x09
STRICT_ARRAY = 0x0a
DATE = 0x0b
LONG_STRING = 0x0c
UNSUPPORTED = 0x0d
RECORD_SET = 0x0e
XML_OBJECT = 0x0f
TYPED_OBJECT = 0x10
Binary Format

AMF format for a value/object consists of a type byte (see above) followed by zero or more bytes. This section describes the bytes following the type byte for various types.


NUMBER (type byte: 0x00)

Numbers are stored as 8 byte (big endian) float double. On x86 you can just byteswap a double to encode it correctly.


BOOLEAN (type byte: 0x01)

A boolean is encoded in one byte. FIXME: is true sent as 0xff? 0x01?


STRING (type byte: 0x02)

A string is encoded as a 2 byte (big endian) count (number of bytes) followed by that many bytes of text. Note: there is no null terminator.

I think the text is assumed to be UTF-8. Can someone double check me on this?


NULL_VALUE (type byte: 0x05)

A null has zero bytes following the type byte


UNDEFINED (type byte: 0x06)

A undefined has zero bytes following the type byte


OBJECT (type byte: 0x08)

An object is encoded as a series of key/value pairs. The key is encoded as a STRING (above) WITH NO TYPE BYTE, and the value is any AMF value.

The object encoding is terminated by 0x000009 (that is a zero length string key, followed by the OBJECT_END type byte described below.


OBJECT_END (type byte: 0x09)

This is not really a value, but a marker for the end of an OBJECT. See above.


STRICT_ARRAY (type byte: 0x0a)

This is the encoding for arrays such as ["foo", "bar", 1, 2, 3]. For a hash (a set of key/value pairs) you'll need to use OBJECT above.

An array is encoded as 4 byte (big endian) integer which is the number of elements in the array, followed by that many AMF values.

That's it. There's no terminator of any kind.


Use in shared object files

While most AMF objects are just a value, there is a special variation used by shared object files for properties. Rather than start with the type field, followed by the length, it starts with a byte count, then the name, and then the regular AMF type field, the length, and then the data.


3.4 客户端和服务器的连接过程
3.4.1客户和服务器的握手

您的浏览器可能不支持显示此图像。

   Flash Player 以系统时间作为种子通过某种算法生成的数字签名,大小是 1537 字节向服务器发起第一次握手,服务器根据客户端的数字签名产生一个 3073 字节的验证包,给客户端,客户端在接受到服务器的回应以后会发送一个 1536 字节的回复。

具体的流程:


发送第一次握手包 handshark1
接收第二次握手包 handshark2
发送的三次握手包 handshark3

第一个握手包 handshark1 和服务器的回复握手包 handshark2 都是以 0X03 开头。这三次握手不是 RTMP 协议本身的内容,所以在这并没有包含 RTMP  的协议头。是服务器的厂家自己产品做验证用的,严格的说就是你必须用  Adobe 的客户端和服务器才能使用我的协议。


3.4.2客户和服务器通信

   具体连接和请求视频的过程


发送 rtmp_connect 命令
. 发送本地带宽消息 . 默认是 125000
服务器返回服务器带宽信息
服务器返回本地带宽信息
服务器返回连接成功消息 "NetConnection.Connect.Success"
客户端发送创建流请求 encodeCreateStreamPacket
服务器返回创建流成功消息
客户端发送播放文件消息 Rtmp_Play
服务器返回 TYPE_CHUNK_SIZE 消息
服务器返回开始播放消息 "NetStream.Play.Start"
服务器返回视频信息 (TYPE_STREAM_METADATA) ,包括大小,宽高,速率等等信息--文件长度可以在这里推算出来

RTMP 的净核决定了内容服务, adobe 的服务器采用的 AMF 格式的字串命令来控制视频的传输和播放,具体的字串命令信息如下:(注:字串的定义有厂家( adobe )自己定义,只要满足 AMF 的格式就可以)


 
 
NetConnection.Call.Failed
NetConnection.Call.BadVersion 
NetConnection.Connect.AppShutdown
NetConnection.Connect.Closed
NetConnection.Connect.Rejected
NetConnection.Connect.Success
NetStream.Clear.Success
NetStream.Clear.Failed
NetStream.Publish.Start
NetStream.Publish.BadName
NetStream.Failed
NetStream.Unpublish.Success
NetStream.Record.Start
NetStream.Record.NoAccess
NetStream.Record.Stop
NetStream.Record.Failed
NetStream.Play.InsufficientBW
NetStream.Play.Start
NetStream.Play.StreamNotFound
NetStream.Play.Stop
NetStream.Play.Failed
NetStream.Play.Reset
NetStream.Play.PublishNotify
NetStream.Play.UnpublishNotify
NetStream.Data.Start
Application.Script.Error
Application.Script.Warning
Application.Resource.LowMemory
Application.Shutdown
Application.GC
Play
Pause
demoService.getListOfAvailableFLVs
getStreamLength
connect
app
flashVer
swfUrl
tcUrl
fpad
capabilities
audioCodecs
audioCodecs
videoCodecs
videoFunction
pageUrl
createStream
deleteStream
duration
framerate
audiocodecid
audiodatarate
videocodecid
videodatarate
height
width
3.4.2数据的萃取

      在服务器返回开始播放消息 "NetStream.Play.Start" 之后,服务器就会开始给客户端传输数据了,一般数据的萃取都是先解析协议的头,然后根据协议头中数据类型和净核长度就可以把数据部分取出, RTMP 协议也是这样。

struct RTMP_HEAD

{

          char cChannelid : 6;// 第一个字节的后 6 位

          char cCheadsize ; // 第一个字节的头两位


      char cTimer[3];  // 三个字节表示的时间信息


      char cLength[3]; // 三个字节表示的长度


      char cDatatype; // 数据类型


      char sStreamid[4]; // 流标识


}


      首先判断 cDatatype 是那种类型,然后根据不同的类型进行萃取数据部分,进行不同的处理,获取视频的数据的方式先看是否是一下的类型:


0×08 Audio Data packet containing audio
0×09 Video Data packet containing video data

 
根据净核的长度读取出内存中的音视频数据,这里的音视频数据是有一定编码格式的数据,这个取决于应用的具体配置, Flash play 使用的是 FLV 的格式。要对这部分数据进行存取,还有做一部分工作,对 FLV 的视频数据进行去壳,取出数据保存文件就可以了。


文章来源:http://fengqing888.blog.163.com/blog/static/33011416201171695632331

posted @ 2011-08-16 09:57 FengRalf 阅读(539) | 评论 (0)编辑 收藏
[导入]RTSP协议详解

相关参考: http://blog.csdn.net/chenyanxu/article/details/2728427

相关参考:

http://hi.baidu.com/13764969808/blog/item/268ff5fd86bb70f4fd037f79.html

http://www.cnblogs.com/Jimmly/archive/2009/07/27/1531999.html

关于 RTSP.

RTSP协议是一个非常类似HTTP协议的流控制协议。它们都使用纯文本来发送信息,而且rtsp协议的语法也和HTTP类似。Rtsp一开始这样设计,也是为了能够兼容使用以前写的HTTP协议分析代码 。这是个好消息。

它们主要的区别是HTTP协议是没有状态的, http协议在发送一个命令后,连接会断开,而且命令之间没有依赖性。不同的是RTSP的命令需要知道现在正处于一个什么状态,也就是说rtsp的命令总是按照顺序来发送,某个命令总在另外一个命令之前要发送。Rtsp不管处于什么状态都不会去断掉连接。

HTTP 协议默认使用80端口,而RTSP 默认使用554端口。如果一些服务器因为某些安全的原因而封掉了这个端口,那代理和防火墙可能不让RTSP消息通过,需要管理员去放开554端口,而使得rtsp协议能通过。

 


RTSP 并非只是微软在用!

这是一个公开的规范,在这个规范上开发了很多的流服务器。甚至Linux服务提供者和苹果的程序员也使用rtsp协议以及Real Networks流媒体。似乎整个世界的网络流传输都用这个协议。然而,微软并不只在rtsp上有所作为。

 


微软和RTSP.

在写这个文档的时候,微软正处于从首选MMS协议转换到首选采用RTSP协议的过程中。这个说明在Media Player9.0版本和流媒体服务器2003版本之后,我们会看到微软将rtsp协议作为流媒体传输的主要协议 。

随着时间慢慢的流逝,我们会发现mms协议正逐步走出人们的视野。It is only assumed that this is so MS can say they are being open with their protocols (rtsp is an open standard) while at the same time disregarding the need to publicise their own MMS protocol once its gone from media player. 然而,mms还没有真的死亡,至少在接下来的几年中我们依然可以看到它在流媒体传输中的身影。

 


是否微软的RTSP协议和标准的开放式RTSP不同?

是的。跟在RFC2326(1998年四月)中定义的原始RTSP协议相比,微软的rtsp协议有一些轻微的改动。我们网站上有本文档(还有后续版本)和一个简单的研究,它们可以帮助你了解这些信息。

 


区别在哪儿?

微软的rstp规范与标准rtsp协议相比最主要的改动是发送包payloads到客户端的方式,另外还有一些请求命令有一些改动。传输单个媒体包的机制并没有文档(就 我目前所知),这可能是微软要保留的信息。

就像MMS和HTTP 1.0 流协议使用一个媒体数据包头一样,RTSP也有。但是微软的数据包头格式没有在任何的rtsp文档中注明。在企图连接微软的rtsp服务器时,这是主要的问题。

微软RTSP协议的命令采用的语法和标准rtsp协议的命令语法一样,只有一些小的修改和添加,可以通过阅读网上的一些文档,就可以知道怎么去组成这些命令。微软rtsp命令部分已经有文档了。

 

 

 

 

 

 

 

 


一次典型的RTSP协议传输过程

这个例子为了简略,没有把发送接收的包放上来

 


To Server =>                                 NETWORK                         <= To Client

 

客户端连服务器的554端口

 

客户端发送“DESCRIBE”命令

 

                                               服务器返回标准rtsp头

                                               这个rtsp头和数据实体包含ASF文件头信息

以及所有的和媒体文件相关的流bit rate data

 

客户端发送“SETUP” 音频流媒体建立命令(stream 1)

                                              

服务器返回标准rtsp头

 

客户端发送“SETUP” 视频流媒体建立命令(stream 2)

 

                                               服务器返回标准rtsp头

 

客户端发送“PLAY” 命令

                                              

服务器返回标准rtsp头

 

客户端发送 “SET_PARAMETER” 命令

这个命令还包含了一些客户端发送给服务器的信息,比如客户端的操作系统,CPU类型,播放器版本,日期时间等信息。 消息格式是tagged XML.

 

服务器返回标准rtsp头

 

#### 服务器即将开始一个流,发送媒体数据包(包含媒体数据包头),请看接下来的 ####

 

当要断开这个流的时候,服务器会向客户端发送一个EOF指示

 

                                               服务器断开socket连接

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


一个典型的发给服务器的RTSP命令

 

DESCRIBE rtsp://wm.microsoft.com/ms/video/0001-hi.wmv RTSP/1.0

User-Agent: WMPlayer/9.0.0.2980 guid/3300AD50-2C39-46C0-AE0A-81D88F547805

Accept: application/sdp

Accept-Charset: UTF-8, *;q=0.1

X-Accept-Authentication: NTLM, Digest, Basic

Accept-Language: en-GB, *;q=0.1

CSeq: 1

Supported: com.microsoft.wm.srvppair, com.microsoft.wm.sswitch, com.microsoft.wm.eosmsg, com.microsoft.wm.predstrm

 

 

注意:

DESCRIBE rtsp://wm.microsoft.com/ms/video/0001-hi.wmv RTSP/1.0

这是要连接的url(服务器域名和流路径),后面跟着RTSP的版本。

 

User-Agent: WMPlayer/9.0.0.2980 guid/3300AD50-2C39-46C0-AE0A-81D88F547805

这条表示了客户端使用的是什么播放器,以及播放器的版本,再跟着一个独特的GUID。

 

X-Accept-Authentication: NTLM, Digest, Basic

客户端可以接受的authentication 类型

 

注意CSeq 要从1开始。服务器针对请求命令的应答也应该有Cseq: 加上数字 ,这样可以知道是针对哪条请求发的应答。

在客户端发送一个请求命令,得到成功的应答后,再发送下一条命令,CSeq的值要加1。

 

 


一个典型的RTSP应答消息,它们跟HTTP的消息非常的相似

一个针对客户端发的DESCRIBE命令,服务器的应答例子如下所示:

 

<<<HEADER START>>>

 

RTSP/1.0 200 OK

Content-Type: application/sdp

Vary: Accept

X-Playlist-Gen-Id: 27006

X-Broadcast-Id: 0

Content-Length: 3324

Date: Tue, 18 Nov 2003 15:57:05 GMT

CSeq: 1

Server: WMServer/9.0.0.3372

Supported: com.microsoft.wm.srvppair, com.microsoft.wm.sswitch, com.microsoft.wm.eosmsg, com.microsoft.wm.fastcache, com.microsoft.wm.packetpairssrc

Last-Modified: Tue, 18 Jun 2002 21:05:39 GMT

Cache-Control: x-wms-content-size=23180160, max-age=86399, must-revalidate, proxy-revalidate

Etag: "23180160"

 

 

 

 

<<<BODY START>>> ( 两个“/r/n”指示本SDP数据的开始 ).

<<< 这是Session Description Protocol 协议>>>

 

v=0

o=- 200311171721060249 200311171721060249 IN IP4 127.0.0.1

s=<No Title>

c=IN IP4 0.0.0.0

b=AS:1091

a=maxps:13632

t=0 0

a=control:rtsp://wm.microsoft.com/ms/video/0001-hi.wmv/

a=etag:{9D7121C3-1A1B-8ED6-6675-CB15D19D1FB7}

a=range:npt=3.100-173.903

a=recvonly

a=pgmpu:data:application/x-wms-contentdesc,8,language,31,0,,5,title,31,0,,6,author,31,0,,9,copyright,31,0,,35,WMS_CONTENT_DESCRIPTION_DESCRIPTION,31,0,,30,WMS_CONTENT_DESCRIPTION_RATING,31,0,,44,WMS_CONTENT_DESCRIPTION_SERVER_BRANDING_INFO,31,12,WMServer/9.0,51,WMS_CONTENT_DESCRIPTION_PLAYLIST_ENTRY_START_OFFSET,3,4,3100,47,WMS_CONTENT_DESCRIPTION_PLAYLIST_ENTRY_DURATION,3,6,170803,58,WMS_CONTENT_DESCRIPTION_COPIED_METADATA_FROM_PLAYLIST_FILE,3,1,1,42,WMS_CONTENT_DESCRIPTION_PLAYLIST_ENTRY_URL,31,17,0001-hi.wmv%0D%0A

a=pgmpu:data:application/vnd.ms.wms-hdr.asfv1;base64,Mcay...dY5mm2QCAQ==

m=audio 0 RTP/AVP 96

b=AS:35

b=RS:0

b=RR:0

a=rtpmap:96 x-asf-pf/1000

a=control:audio

a=stream:1

m=application 0 RTP/AVP 96

b=RS:0

b=RR:0

a=rtpmap:96 x-wms-rtx/1000

a=control:rtx

a=stream:65536

m=video 0 RTP/AVP 96

b=AS:471

b=RS:0

b=RR:0

a=rtpmap:96 x-asf-pf/1000

a=control:stream=2

a=stream:2

 

以/r/n/r/n结束

 

 

看下面这行:

a=pgmpu:data:application/vnd.ms.wms-hdr.asfv1;base64, Mcay..…==

这是真实的ASF文件头数据(被Base64编码过)。在将这部分头数据写到文件之前需要Base64解码成标准的ascii码。

 

SDP实体数据也告诉我们在媒体数据中都有些什么流
这个文件有2个媒体流:

ID = 1 有一个“audio”标志的音频流

ID = 2 有一个“stream=2”标志的视频流

还有第三个以“rtx”标志的流,这是一个控制流,并不携带任何的媒体内容。这个控制流使用stream ID = 65536.

 

看下面这行:

a=pgmpu:data:application/x-wms-contentdesc, …..

这表示了紧跟的数据是一个内容描述对象。

 

 

 

 


标准RTSP 消息的错误代码– 在应答消息的第一行表示

 

 ”100” ; Continue (all 100 range)

 “200” ; OK

 ”201” ; Created

 ”250” ; Low on Storage Space

 ”300” ; Multiple Choices

 ”301” ; Moved Permanently

 ”302” ; Moved Temporarily

 ”303” ; See Other

 ”304” ; Not Modified

 ”305” ; Use Proxy

 ”350” ; Going Away

 ”351” ; Load Balancing

 ”400” ; Bad Request

 ”401” ; Unauthorized

 ”402” ; Payment Required

 ”403” ; Forbidden

 ”404” ; Not Found

 ”405” ; Method Not Allowed

 ”406” ; Not Acceptable

 ”407” ; Proxy Authentication Required

 ”408” ; Request Time-out

 ”410” ; Gone

 ”411” ; Length Required

 ”412” ; Precondition Failed

 ”413” ; Request Entity Too Large

 ”414” ; Request-URI Too Large

 ”415” ; Unsupported Media Type

 ”451” ; Parameter Not Understood

 ”452” ; reserved

 ”453” ; Not Enough Bandwidth

 ”454” ; Session Not Found

 ”455” ; Method Not Valid in This State

 ”456” ; Header Field Not Valid for Resource

 ”457” ; Invalid Range

 ”458” ; Parameter Is Read-Only

 ”459” ; Aggregate operation not allowed

 ”460” ; Only aggregate operation allowed

 ”461” ; Unsupported transport

 ”462” ; Destination unreachable

 ”500” ; Internal Server Error

 ”501” ; Not Implemented

 ”502” ; Bad Gateway

 ”503” ; Service Unavailable

 ”504” ; Gateway Time-out

 ”505” ; RTSP Version not supported

 ”551” ; Option not supported

 

 

 

 

 

 

 

 

 

 

 

 


RTSP数据包头(每一个媒体数据包的开头)

二进制包头数据后面紧跟着媒体数据包(asf/wmv 等等)。

Values are in Big Endian order. (not little endian as in mms and http protocols).

 

--------这些数据位在公开的RTSP 文档中也指示了-------

 

BYTE                 “$” or 0x24

BYTE                    Channel id ,一般= 0x00, 你可以看到“P” 或者 0x50 for packet pairs data, 看下面的描述.

WORD               数据包的长度(从接下来的区域算起)

 

-------- 接下来的数据位表示的含义还没有确定,微软也许会指出-----------

 

WORD      ???    填充0x80E0

 

WORD                   序列号。这个值被初始化成一个随即的值,然后在每一个数据包发送时加1。  在这个值达到0xffff时,它将设置成0。跟其他协议相比,这个值得范围比较小(16位),使得它不能在写媒体数据到文件中时做为有指导性的序列号使用。大的流媒体文件有很多的数据包,包的数量超过了他的范围,所以可能会发生相同序列号的包。只使用这个序列号来作错误检验——缺少了某一个序列号的包意味着发生了丢包错误。

 

DWORD                发送时间。This is stated in milliseconds and shows the time that this media packet should be presented. 预先录制的文件设置T = 0 ,实况流设置一个不同于0的值。

 

DWORD                ??? 固定的一个值. 它是一个随即值,但是一旦一个rtsp会话建立,这个值就一直保持不变,所有的数据包都是这个值。可以使用这个值作为每次会话的一个ID,新的rtsp会话会有新的值。

 

BYTE                     标志位, 看下面:

                                Bit 0 (lsb)      ? = 0

                                Bit 1               ? = 0

                                Bit 2               ? = 0

                                Bit 3               ? = 0

                                Bit 4               Duration field present in pre header if set (see below)

                                Bit 5               ? = 0

                                Bit 6               ? = 1 (总是1)

                                Bit 7 (msb)    被设置成1,表示数据包含有一个关键桢

 

BYTE                     ??? 总是设置成0

 

WORD                   包长度。此16位表示从上面标志位域开始的包长度。

 

DWORD                [可选的] 持续时间。只有上面的标志位的Bit4 被设置了才会有这个域,否则就没有这个域。表示为多少毫秒,指出了传输的媒体包的总持续时间。

 

<<< 下面跟着媒体数据, like 82 00 00 ….. >>>

 

 

 

 

 

 

 

 

 

 


在RTSP请求和应答中使用的有用的标签值:

 

CSeq:                                    命令的序列号,逐1增加。

                                               所有的请求和应答都用得到。

 

Content-Length:                                  这个标记的存在说明后面有实体数据,而且给出了这个数据块的大小,单位是byte

 

X-Playlist-Gen-Id:                               用来检查播放列表是否有效。这个标记最初在客户端发送DESCRIBE命令后使用。

                                               客户端在发送“SETUP”命令给服务器时必须回应一样的值

                                              

 

X-Playlist-Seek-Id:                              值必须和X-Playlist-Gen-Id 域的值相同,在PLAY请求命令中使用.

 

Blocksize:                                             媒体包的总长度,单位是byte

 

Session:                                                 Session ID是用作客户端和服务器之间是否是正确的连接。在客户端发送SETUP命令,服务器会在应答消息头里面发送这个值给客户端。 We only see the Session value on the first stream selected (usually this is the audio stream)。 Session 值相当的长,一共有20个阿拉伯数字。

                                                                紧跟着Session值, 你可以看到一个值:       “timeout= xxxx”。. 这是服务器需要得到回应或者ACK回应(为了保持连接)的时间。客户端必须在这个时段内发送一个ACK ,要不然连接就要被强制中断。一个ACK就是发送一条GET_PARAMETER命令到服务器。

 

X-Accept-Authentication:                 允许的authentication 方法

                                                                NTLM, Digest 和 Basic 是标准的

 

X-Broadcast-Id:                                  是否是实况或者是先期录制的流。

                                                                0 表示先期录制,其他的值表示是实况。

 

Range:                                                   Range is the offset and end time positions to stream the media. For a zero start and full file stream, this value is set to:   npt=0.000-

                                                                where 0.000 is the offset and –0.000 (optional) is the ending time. Values are stated in seconds.

 

Speed:                                                    用来调整传输到客户端的流得速度。假如你的带宽可以接受更高速的数据传送,这个域的值可以设置大于1来加速下载数据

普通情况  Speed: 1.0       i.e. x1 rate

                                                                Media player 使用 :     Speed: 1.294

这个主要取决于你的网络连接速度。

 

Server:                                                   服务器类型和软件版本

 

EOF:                                                       文件结束标记,也是流的结束标记

 

Date:                                                      日期时间,下面举个例子:

Tue, 18 Nov 2003 15:57:07 GMT

 

Bandwidth:                                           流需要的最大带宽,bits/秒

 

Transport:                                             使用什么协议来传输数据,比如TCP或者UDP等

 

Etag:                                                      实体标记Entity tag,是一个分配给会话的值,就像"23180160"

 

Supported:                                            支持的COM modules , 有的是可选的.

com.microsoft.wm.srvppair       - packet pairs at server

com.microsoft.wm.sswitch         - stream ID selection com.microsoft.wm.eosmsg       - end of stream message com.microsoft.wm.fastcache       - fast cache for buffering com.microsoft.wm.packetpairssrc.  - packet pairs

 

Content-Type:                                     此域用来表示命令或者应答的用意

                                                                下面是常用的几种类型:

 

                                                                application/x-wms-Logconnectstats

                                                                这个在SET_PARAMETER命令中用到,表示将客户端的信息登记到服务器上。

 

                                                                application/sdp

                                                                这个表示接下来数据包里面的是sdp数据,它是在服务器对DESCRIBE命令的应答包中。

 

                                                                application/x-wms-contentdesc

                                                                表示紧跟的数据是一个内容描述对象,它设置the layout of the dialog.

 

                                                                application/vnd.ms.wms-hdr.asfv1

                                                                表示跟着一个流媒体头信息(ASF header),

                                                                可以用BASIC 或者DIGEST来解码。

 

                                                                application/x-rtsp-packetpair

                                                                Packet Pair data is random non-compressible data and is sent to the client and timed for response times. 它被用来确定连接的可用带宽。Packet pair data 是可选的,你不必经常去请求这个数据。 这个是在发送GET_PARAMATER命令到服务器时,用到的。.


 


文章来源:http://fengqing888.blog.163.com/blog/static/33011416201171695521699

posted @ 2011-08-16 09:55 FengRalf 阅读(1923) | 评论 (0)编辑 收藏
[导入]RTSP协议

RTSP协议

    RTSP(Real Time Stream Protocol,实时流协议)是应用级协议,控制实时数据的发送。RTSP提供了一个可扩展框架,使实时数据,如音频与视频的受控、点播成为可能。数据源包括现插数据与存储在剪辑中的数据。该协议目的在于控制多个数据发送连接,为选择发送通道如UDP、多播UDP与TCP等提供途径,并为选择基于RTP 上发送机制提供方法。

一.简介

1.目的

实时流协议建立并控制一个或几个时间同步的连续流媒体。尽管连续媒体流与控制流交叉是可能的,通常它本身并不发送连续流。换言之,RTSP充当多媒体服务器的网络远程控制。RTSP连接没有绑定到传输层连接,如TCP。在RTSP连接期间,RTSP用户可打开或关闭多个对服务器的可靠传输连接以发出 RTSP请求。此外,可使用无连接传输协议,如UDP。RTSP流控制的流可能用到RTP,但RTSP操作并不依赖用于携带连续媒体的传输机制。实时流协议在语法和操作上与HTTP 1.1类似,因此HTTP的扩展机制大都可加入RTSP。协议支持的操作如下:

(1)从媒体服务器上检索媒体

用户可通过HTTP或其他方法提交一个演示描述。如演示是多播,演示时就包含用于连续媒体的多播地址和端口。如演示仅通过单播发送给用户,用户为了安全应提供目的地址。

(2)媒体服务器邀请进入会议

媒体服务器可被邀请参加正进行的会议,或回放媒体,或记录其中一部分或全部。这种模式在分布式教育应用上很有用,会议中几方可轮流按远程控制按钮。

(3)将媒体加到现成讲座中

例如,服务器告诉用户可获得附加媒体内容。这对现场讲座显得尤其有用。如HTTP 1.1中类似,RTSP请求可由代理、通道与缓存处理。

2.协议特点

RTSP有如下特性。

(1) 可扩展性:新方法和参数很容易加入RTSP。

(2) 易解析:RTSP可由标准HTTP或MIME解析器解析。

(3) 安全:RTSP使用网页安全机制。

(4) 独立于传输:RTSP可使用不可靠数据报协议(EDP)、可靠数据报协议(RDP);如要实现应用级可靠,可使用可靠流协议。

(5) 多服务器支持:每个流可放在不同服务器上,用户端自动与不同服务器建立几个并发控制连接,媒体同步在传输层执行。

(6) 记录设备控制:协议可控制记录和回放设备。

(7) 流控与会议开始分离:仅要求会议初始化协议提供,或可用来创建惟一会议标识号。特殊情况下,可用SIP或H.323来邀请服务器入会。

(8) 适合专业应用:通过SMPTE时标,RTSP支持帧级精度,允许远程数字编辑。

(9) 演示描述中立:协议没强加特殊演示或元文件,可传送所用格式类型;然而,演示描述至少必须包括一个RTSP URL。

(10) 代理与防火墙友好:协议可由应用和传输层防火墙处理。防火墙需要理解SETUP方法,为UDP媒体流打开一个“缺口”。

(11) HTTP友好:此处,RTSP明智地采用HTTP观念,使现在结构都可重用。结构包括Internet内容选择平台(PICS)。由于在大多数情况下控制连续媒体需要服务器状态,RTSP不仅仅向HTFP添加方法。

(12) 适当的服务器控制:如用户启动一个流,必须也可以停止一个流。

(13) 传输协调:实际处理连续媒体流前,用户可协调传输方法。

(14) 性能协调:如基本特征无效,必须有一些清理机制让用户决定哪种方法没生效。这允许用户提出适合的用户界面。

3.扩展RTSP

由于不是所有媒体服务器有着相同的功能,媒体服务器有必要支持不同请求集。RTSP可以如下三种方式扩展:

(1) 以新参数扩展。如用户需要拒绝通知,而方法扩展不支持,相应标记就加人要求的段中。

(2) 加入新方法。如信息接收者不理解请求,返回501错误代码,发送者不应再次尝试这种方法。用户可使用OPTIONS方法查询服务器支持的方法。服务器使用公共响应头列出支持的方法。

(3) 定义新版本协议,允许改变所有部分(协议版本号位置除外)。

4.操作模式

每个演示和媒体流可用RTSP URL识别。演示组成的整个演示与媒体属性由演示描述文件定义。使用HTTP或其他途径用户可获得这个文件,它没有必要保存在媒体服务器上。为了说明这个问题,假设演示描述了多个演示,其中每个演示维持了一个公共时间轴。为简化说明,且不失一般性,假定演示描述的确包含这样一个演示。演示可包含多个媒体流。除媒体参数外,网络目标地址和端口也需要决定。

下面区分几种操作模式。

(1)单播:用户选择的端口号将媒体发送到RTSP请求源。

(2)服务器选择地址多播:媒体服务器选择多播地址和端口,这是现场直播或准点播常用的方式。

(3)用户选择地址多播:如服务器加入正在进行的多播会议,多播地址、端口和密钥由会议描述给出。

5.RTSP状态

RTSP控制通过单独协议发送的流,与控制通道无关。例如,RTSP控制可通过TCP连接,而数据流通过UDP。因此,即使媒体服务器没有收到请求,数据也会继续发送。在连接生命期,单个媒体流可通过不同TCP连接顺序发出请求来控制。所以,服务器需要维持能联系流与RTSP请求的连接状态。 RTSP中很多方法与状态无关,但下列方法在定义服务器流资源的分配与应用上起着重要的作用:

(1) SETUP:让服务器给流分配资源,启动RTSP连接。

(2) PLAY与RECORD:启动SETUP分配流的数据传输。

(3) PAUSE:临时停止流,而不释放服务器资源。

(4) TEARDOWN:释放流的资源,RTSP连接停止。

标识状态的RTSP方法使用连接头段识别RTSP连接,为响应SETUP请求,服务器连接产生连接标识。

6.与其他协议的关系

RTSP在功能上与HTTP有重叠,与HTTP相互作用体现在与流内容的初始接触是通过网页的。目前的协议规范目的在于允许在网页服务器与实现 RTSP媒体服务器之间存在不同传递点。例如,演示描述可通过HTTP和RTSP检索,这降低了浏览器的往返传递,也允许独立RTSP服务器与用户不全依靠HTTP。

但是,RTSP与HTTP的本质差别在于数据发送以不同协议进行。HTTP是不对称协议,用户发出请求,服务器作出响应。RTSP中,媒体用户和服务器都可发出请求,且其请求都是无状态的;在请求确认后很长时间内,仍可设置参数,控制媒体流。重用HTTP功能至少在两个方面有好处,即安全和代理。要求非常接近时,在缓存、代理和授权上采用HTTP功能是有价值的。

当大多数实时媒体使用RTP作为传输协议时,RTSP没有绑定到RTP。RTSP假设存在演示描述格式可表示包含几个媒体流的演示的静态与临时属性。

二. 协议参数

1.RTSP版本

H.321采用,用RTSP代替HTTP。

2.RTSPURL

“rksp"和“rtspu"方案用于指RTSP协议使用的网络资源,为RTSP URL定义方案特定的语法和语义。

3.会议标识

会议标识对RTSP来说是模糊的,采用标准URI编码方法编码,可包含任何八位组数值。会议标识必须全局惟一。

4.连接标识

连接标识是长度不确定的字符串,必须随机选择,至少要8个八位组长,使其很难被猜出。

5.SMPTE相关时标

SMPTE相关时标表示相对剪辑开始的时间,相关时标表示成SMPTE时间代码,精确到帧级。时间代码格式为小时:分钟:秒:帧。缺省smpte格式是"SMPTE 30",帧速率为每秒29.97帧。其他SMPTE代码可选择使用smpte时间获得支持(如"SMPIE 25")。时间数值中帧段值可从0到29。每秒30与29.97帧的差别可将每分钟的头两帧丢掉来实现。如帧值为零,就可删除。

6.正常播放时间

正常播放时间(NPT)表示相对演示开始的流绝对位置。时标由十进制分数组成。左边部分用秒或小时、分钟、秒表示;小数点右边部分表示秒的部分。演示的开始对应0.0秒,负数没有定义。特殊常数定义成现场事件的当前时刻,这也许只用于现场事件。直观上,NPT是联系观看者与程序的时钟,通常以数字式显示在VCR上。

7.绝对时间

绝对时间表示成ISO 8601时标,采用UTC(GMT)。

8.可选标签

可选标签是用于指定RTSP新可选项的惟一标记。这些标记用在请求和代理-请求头段。当登记新RTSP选项时,需提供下列信息:

(1)名称和描述选项。名称长度不限,但不应该多于20个字符。名称不能包括空格、控制字符。

(2)表明谁改变选项的控制。如IETF,ISO,ITU-T,或其他国际标准团体、联盟或公司。

(3)深入描述的参考,如RFC、论文、专利、技术报告、文档源码和计算机手册。

(4)对专用选项,附上联系方式。

三. RTSP信息

RTSP是基于文本的协议,采用ISO 10646字符集,使用UTF-8编码方案。行以CRLF中断,但接收者本身可将CR和LF解释成行终止符。基于文本的协议使以自描述方式增加可选参数更容易。由于参数的数量和命令的频率出现较低,处理效率没引起注意。文本协议很容易以脚本语言(如:Tcl,Visual Basic与Perl)实现研究原型。

ISO 10646字符集避免敏感字符集切换,但对应用来说不可见。RTCP也采用这种编码方案。带有重要意义位的ISO 8859-1字符表示如100001x 10x x x x x x。RTSP信息可通过任何低层传输协议携带。

请求包括方法、方法作用于其上的对象以及进一步描述方法的参数。方法也可设计为在服务器端只需要少量或不需要状态维护。当信息体包含在信息中,信息体长度由如下因素决定:

(1)不管实体头段是否出现在信息中,不包括信息体的响应,信息总以头段后第一个空行结束。

(2)如出现内容长度头段,其值以字节计,表示信息体长度。如未出现头段,其值为零。

(3)服务器关闭连接。

注意,RTSP目前并不支持HTTP 1.1“块”传输编码,需要有内容长度头。假如返回适度演示描述长度,即使动态产生,使块传输编码没有必要,服务器也应该能决定其长度。如有实体,即使必须有内容长度,且长度没显式给出,规则可确保行为合理。

从用户到服务器端的请求信息在第一行内包括源采用的方法、源标识和所用协议版本。RTSP定义了附加状态代码,但没有定义任何HTTP代码。

四. 实体

如不受请求方法或响应状态编码限制,请求和响应信息可传输实体,实体则由实体头文件和实体体组成,有些响应仅包括实体头。在此,根据谁发送实体、谁接收实体,发送者和接收者可分别指用户和服务器。

实体头定义实体体可选元信息,如没有实体体,指请求标识的资源。扩展头机制允许定义附加实体头段,而不用改变协议,但这些段不能假定接收者能识别。不可识别头段应被接收者忽略,而让代理转发。

五. 连接

RTSP请求可以几种不同方式传送:

·             持久传输连接,用于多个请求/响应传输。

·             每个请求/响应传输一个连接。

·             无连接模式。

传输连接类型由RTSP URL来定义。对“rtsp'’方案,需要持续连接;而"rtspu"方案,调用RTSP请求发送,而不用建立连接。

不像HTTP,RTSP允许媒体服务器给媒体用户发送请求。然而,这仅在持久连接时才支持,否则媒体服务器没有可靠途径到达用户,这也是请求通过防火墙从媒体服务器传到用户的惟一途径。

六. 方法定义

方法记号表示资源上执行的方法,它区分大小写。新方法可在将来定义,但不能以$开头。已定义方法如表14-03-1所示。

表14-03-1   RTSP方法


方法

方向

对象

要求

含义

DESCRIBE

C->S

P, S

推荐

检查演示或媒体对象的描述,也允许使用接收头指定用户理解的描述格式。DESCRIBE的答复-响应组成媒体RTSP初始阶段

ANNOUNCE

C->S

S->C

P, S

可选

当从用户发往服务器时,ANNOUNCE将请求URL识别的演示或媒体对象描述发送给服务器;反之,ANNOUNCE实时更新连接描述。如新媒体流加入演示,整个演示描述再次发送,而不仅仅是附加组件,使组件能被删除

GET_PARAMETER

C->S

S->C

P, S

可选

GET_PARAMETER请求检查RUL指定的演示与媒体的参数值。没有实体体时,GET_PARAMETER也许能用来测试用户与服务器的连通情况

OPTIONS

C->S

S->C

P, S

要求

可在任意时刻发出OPTIONS请求,如用户打算尝试非标准请求,并不影响服务器状态

PAUSE

C->S

P, S

推荐

PAUSE请求引起流发送临时中断。如请求URL命名一个流,仅回放和记录被停止;如请求URL命名一个演示或流组,演示 或组中所有当前活动的流发送都停止。恢复回放或记录后,必须维持同步。在SETUP消息中连接头超时参数所指定时段期间被暂停后,尽管服务器可能关闭连接 并释放资源,但服务器资源会被预订

PLAY

C->S

P, S

要求

PLAY告诉服务器以SEFUP指定的机制开始发送数据;直到一些SETUP请求被成功响应,客户端才可发布PLAY请 求。PLAY请求将正常播放时间设置在所指定范围的起始处,发送流数据直到范围的结束处。PLAY请求可排成队列,服务器将PLAY请求排成队列,顺序执 行

RECORD

C->S

P, S

可选

该方法根据演示描述初始化媒体数据记录范围,时标反映开始和结束时间;如没有给出时间范围,使用演示描述提供的开始和结束 时间。如连接已经启动,立即开始记录,服务器数据请求URL或其他URL决定是否存储记录的数据;如服务器没有使用URL请求,响应应为201(创建), 并包含描述请求状态和参考新资源的实体与位置头。支持现场演示记录的媒体服务器必须支持时钟范围格式,smpte格式没有意义

REDIRECT

S->C

P, S

可选

重定向请求通知客户端连接到另一服务器地址。它包含强制头地址,指示客户端发布URL请求;也可能包括参数范围,以指明重定向何时生效。若客户端要继续发送或接收URL媒体,客户端必须对当前连接发送TEARDOWN请求,而对指定主执新连接发送SETUP请求

SETUP

C->S

S

要求

对URL的SETUP请求指定用于流媒体的传输机制。客户端对正播放的流发布一个SETUP请求,以改变服务器允许的传输 参数。如不允许这样做,响应错误为"455 Method Not Valid In This State”。为了透过防火墙,客户端必须指明传输参数,即使对这些参数没有影响

SET_PARAMETER

C->S

S->C

P, S

可选

这个方法请求设置演示或URL指定流的参数值。请求仅应包含单个参数,允许客户端决定某个特殊请求为何失败。如请求包含多 个参数,所有参数可成功设置,服务器必须只对该请求起作用。服务器必须允许参数可重复设置成同一值,但不让改变参数值。注意:媒体流传输参数必须用 SETUP命令设置。将设置传输参数限制为SETUP有利于防火墙。将参数划分成规则排列形式,结果有更多有意义的错误指示

TEARDOWN

C->S

P, S

要求

TEARDOWN请求停止给定URL流发送,释放相关资源。如URL是此演示URL,任何RTSP连接标识不再有效。除非全部传输参数是连接描述定义的,SETUP请求必须在连接可再次播放前发布


注:P----演示,S----流,C----用户端,S----服务器端

 

某些防火墙设计与其他环境可能要求服务器插入RTSP方法和流数据。由于插入将使客户端和服务器操作复杂,并增加附加开销,除非有必要,应避免这样做。插入二进制数据仅在RTSP通过TCP传输时才可使用。流数据(如RTP包)用一个ASCII字符$封装,后跟一个一字节通道标识,其后是封装二进制数据的长度,两字节整数。流数据紧跟其后,没有CRLF,但包括高层协议头。每个$块包含一个高层协议数据单元。

当传输选择为RTP,RTCP信息也被服务器通过TCP连接插入。缺省情况下,RTCP包在比RTP通道高的第一个可用通道上发送。客户端可能在另一通道显式请求RTCP包,这可通过指定传输头插入参数中的两个通道来做到。当两个或更多流交叉时,为取得同步,需要RTCP。而且,这为当网络设置需要通过TCP控制连接透过RTP/RTCP提供了一条方便的途径,可能时,在UDP上进行传输。

七. 流水线操作

支持持久连接或无连接的客户端可能给其请求排队。服务器必须以收到请求的同样顺序发出响应。如果请求不是发送给多播组,接收者就确认请求,如没有确认信息,发送者可在超过一个来回时间(RTT)后重发同一信息。

在TCP中RTT估计的初始值为500ms。应用缓存最后所测量的RTT,作为将来连接的初始值。如使用一个可靠传输协议传输RTSP,请求不允许重发,RTSP应用反过来依赖低层传输提供可靠性。如两个低层可靠传输(如TCP和RTSP)应用重发请求,有可能每个包损失导致两次重传。由于传输栈在第一次尝试到达接收者前不会发送应用层重传,接收者也不能充分利用应用层重传。如包损失由阻塞引起,不同层的重发将使阻塞进一步恶化。时标头用来避免重发模糊性问题,避免对圆锥算法的依赖。每个请求在CSeq头中携带一个系列号,每发送一个不同请求,它就加一。如由于没有确认而重发请求,请求必须携带初始系列号。

实现RTSP的系统必须支持通过TCP传输RTSP,并支持UDP。对UDP和TCP,RTSP服务器的缺省端口都是554。许多目的一致的 RTSP包被打包成单个低层PDU或TCP流。RTSP数据可与RTP和RTCP包交叉。不像HTTP,RTSP信息必须包含一个内容长度头,无论信息何时包含负载。否则,RTSP包以空行结束,后跟最后一个信息头。



文章来源:http://fengqing888.blog.163.com/blog/static/33011416201171695155450

posted @ 2011-08-16 09:52 FengRalf 阅读(631) | 评论 (1)编辑 收藏
[导入]RTSP 协议分析 (一)

向博主学习:http://www.cnblogs.com/qingquan/archive/2011/07/14/2106834.html

RTSP 协议分析
1.概述:
 RTSP(Real Time Streaming Protocol),实时流传输协议,是TCP/IP协议体系中的一个应用层协议,由哥伦比亚大学、网景和RealNetworks公司提交的IETF RFC标准。该协议定义了一对多应用程序如何有效地通过IP网络传送多媒体数据。类似HTTP协议的流控制协议。它们都使用纯文本来发送信息,而且rtsp协议的语法也和HTTP类似,和HTTP协议相比RTSP协议所不同的地方是,RTSP协议是有状态的协议,而HTTP是无状态的协议。RTSP通过维护一个session来维护其状态的转换。RTSP协议的默认端口是554,默认的承载协议为TCP。
2.RTSP的特性:
(1).流控分离:从控制逻辑上来说RTSP和FTP相似,控制流和数据流是分开的。
(2).可扩展性:因为RTSP协议是基于文本的协议所以其具有较强的可扩展性。
(3).安全:RTSP 使用网页安全机制。
3.RTSP 协议格式:
请求命令的格式为:
METHOD URL CR LF
Field1:value CR LF
Field2:value CR LF
......
Fieldn:value CR LF
CR LF
应答的格式为:
RTSP/major_version.minor_version status CR LF
Field1:value CR LF
Field2:value CR LF
......
Fieldn:value CR LF
CR LF
4.RTSP的主要命令:

5.RTSP命令的状态转换表

6.RTSP状态码

Status-Code = "100" ; Continue
| "200" ; OK
| "201" ; Created
| "250" ; Low on Storage Space
| "300" ; Multiple Choices
| "301" ; Moved Permanently
| "302" ; Moved Temporarily
| "303" ; See Other
| "304" ; Not Modified
| "305" ; Use Proxy
| "400" ; Bad Request
| "401" ; Unauthorized
| "402" ; Payment Required
| "403" ; Forbidden
| "404" ; Not Found
| "405" ; Method Not Allowed
| "406" ; Not Acceptable
| "407" ; Proxy Authentication Required
| "408" ; Request Time-out
| "410" ; Gone
| "411" ; Length Required
| "412" ; Precondition Failed
| "413" ; Request Entity Too Large
| "414" ; Request-URI Too Large
| "415" ; Unsupported Media Type
| "451" ; Parameter Not Understood
| "452" ; Conference Not Found
| "453" ; Not Enough Bandwidth
| "454" ; Session Not Found
| "455" ; Method Not Valid in This State
| "456" ; Header Field Not Valid for Resource
| "457" ; Invalid Range
| "458" ; Parameter Is Read-Only
| "459" ; Aggregate operation not allowed
| "460" ; Only aggregate operation allowed
| "461" ; Unsupported transport
| "462" ; Destination unreachable
| "500" ; Internal Server Error
| "501" ; Not Implemented
| "502" ; Bad Gateway
| "503" ; Service Unavailable
| "504" ; Gateway Time-out
| "505" ; RTSP Version not supported
| "551" ; Option not supported
| extension-code
extension-code = 3DIGIT
Reason-Phrase = *<TEXT, excluding CR, LF

<下一篇将给出RTSP协议的实例分析>


文章来源:http://fengqing888.blog.163.com/blog/static/33011416201171694056283

posted @ 2011-08-16 09:41 FengRalf 阅读(515) | 评论 (0)编辑 收藏

2011年8月15日

[导入]直接用socket实现HTTP协议

从HTTP服务器上下载一个文件有很多方法,“热心”的微软提供了 WinInet 类,用起来也很方便。当然,我们也可以自己实现这些功能,通过格式化请求头很容易就能实现断点续传和检查更新等等功能 。本文附带的工程中有一个支持 HTTP1.1 协议,直接用 Socket 实现下载功能的 DLL,实现了以下功能:
  1. 连接主机
  2. 格式化请求头
  3. 设置接收,发送超时
  4. 接收并分析回应头

连接,发送,设置超时,接收数据等我就不细说了,windows socket早就做好了,调用相应的函数就OK了。
  要想从服务器下载文件,首先要向服务器发送一个请求。HTTP 请求头由若干行字符串组成。下面结合实例说说 HTTP 请求头的格式。假设要下载 http://www.sina.com.cn/index.html 这个网页 ,那么请求头的写法如下:

第1行:方法,请求的内容,HTTP协议的版本
下载一般可以用GET方法,请求的内容是“/index.html”,HTTP协议的版本是指浏览器支持的版本,对于下载软件来说无所谓,所以用1.1版 “HTTP/1.1”;
“GET /index.html HTTP/1.1”

第2行:主机名,格式为“Host:主机”
在这个例子中是:“Host:www.sina.com.cn”

第3行:接受的数据类型,下载软件当然要接收所有的数据类型,所以:
“Accept:*/*”

第4行:指定浏览器的类型
有些服务器会根据客户服务器种类的不同会增加或减少一些内容,在这个例子中可以这样写:

“User-Agent:Mozilla/4.0 (compatible; MSIE 5.00; Windows 98)”

第5行:连接设置
设定为一直保持连接:“Connection:Keep-Alive”

第6行:若要实现断点续传则要指定从什么位置起接收数据,格式如下:

“Range: bytes=起始位置 - 终止位置”

比如要读前500个字节可以这样写:“Range: bytes=0 - 499”;从第 1000 个字节起开始下载:

“Range: bytes=999 -”

最后,别忘了加上一行空行,表示请求头结束。整个请求头如下:

GET /index.html HTTP/1.1 Host:www.sina.com.cn Accept:*/* User-Agent:Mozilla/4.0 (compatible; MSIE 5.00; Windows 98) Connection:Keep-Alive

CHttpSocket 提供了 FormatRequestHeader()函数,用以格式化输出HTTP请求头。代码如下:

///根据请求的相对URL输出HTTP请求头 const char *CHttpSocket::FormatRequestHeader(char *pServer,char *pObject, long &Length,      char *pCookie,char *pReferer,long nFrom,      long nTo,int nServerType) {  char szPort[10];  char szTemp[20];  sprintf(szPort,"%d",m_port);  memset(m_requestheader,''\0'',1024);   ///第1行:方法,请求的路径,版本  strcat(m_requestheader,"GET ");  strcat(m_requestheader,pObject);  strcat(m_requestheader," HTTP/1.1");          strcat(m_requestheader,"\r\n");   ///第2行:主机     strcat(m_requestheader,"Host:");  strcat(m_requestheader,pServer);     strcat(m_requestheader,"\r\n");   ///第3行:  if(pReferer != NULL)  {   strcat(m_requestheader,"Referer:");   strcat(m_requestheader,pReferer);   strcat(m_requestheader,"\r\n");    }   ///第4行:接收的数据类型     strcat(m_requestheader,"Accept:*/*");     strcat(m_requestheader,"\r\n");   ///第5行:浏览器类型     strcat(m_requestheader,"User-Agent:Mozilla/4.0 (compatible; MSIE 5.00; Windows 98)");     strcat(m_requestheader,"\r\n");   ///第6行:连接设置,保持  strcat(m_requestheader,"Connection:Keep-Alive");  strcat(m_requestheader,"\r\n");   ///第7行:Cookie.  if(pCookie != NULL)  {   strcat(m_requestheader,"Set Cookie:0");   strcat(m_requestheader,pCookie);   strcat(m_requestheader,"\r\n");  }   ///第8行:请求的数据起始字节位置(断点续传的关键)  if(nFrom > 0)  {   strcat(m_requestheader,"Range: bytes=");   _ltoa(nFrom,szTemp,10);   strcat(m_requestheader,szTemp);   strcat(m_requestheader,"-");   if(nTo > nFrom)   {    _ltoa(nTo,szTemp,10);    strcat(m_requestheader,szTemp);   }   strcat(m_requestheader,"\r\n");  }    ///最后一行:空行  strcat(m_requestheader,"\r\n");   ///返回结果  Length=strlen(m_requestheader);  return m_requestheader; }
  请求头发送给服务器后就可以接收来自服务器的回应头了。回应头也是由若干行字符串组成,除了第一行和最后一个空行以外,每一行都由一个域和一个值组成。第一行包括了服务器的回应状态 ,从 2XX 到 5XX,每个状态码都有不同的意思,详细内容可以查看RFC文档下载需要关心的有 :2XX表示成功,可以继续读取数据;3XX表示目标已经转移,新的地址在“Location”域中;4XX表示客户端错,可能是下载地址不对,等等;5XX表示服务器端错 。回应头中的域有“Content-Length”,“Accept-Ranges”,“Content-Type”,“Date”,“Last-Modified”,“Location”等等内容 ,下载比较关心的域有“Content-Length”域和“Location”域。“Content-Length”表示下载文件的大小 ,“Location”表示目标的实际存放位置,当回应码为3XX时就要用该域中的值重新连接。
  附带源码中的 CHttpSocket 类提供了以下几个方法,分别用来读取服务器状态码,某个域的值,回应头中的一行以及整个回应头:
int GetServerState(); //返回服务器状态码 -1表示不成功 int GetField(const char* szSession,char *szValue,int nMaxLength);//返回某个域值,-1表示不成功 int GetResponseLine(char *pLine,int nMaxLength);//获取返回头的一行    const char* GetResponseHeader(int &Length); 
  取得回应头后,如果回应码为2XX并且“Content-Length”的值不等于0就表示可以接收下载文件数据了,接下来的工作就很简单了,调用 CHttpSocket::Recevie()直到接收的数据长度等于“Content-Length”的值就可以了 。
一个完整的使用过程由以下几个步骤组成:
  1. 调用AfxParseURL()分析URL得到Server和下载路径;
  2. 调用CHttpSocket::Socket()创建套接字;
  3. 调用CHttpSocket::Connect()连接服务器;
  4. 调用CHttpSocket::FormatRequestHeader()格式化请求头;
  5. 调用CHttpSocket::SendRequest()向服务器发送请求头;
  6. 调用CHttpSocket::GetServerState()得到回应状态码;
  7. 调用CHttpSocket::GetField("Content-Length")得到下载文件的大小;
  8. 调用CHttpSocket::Receive()接收数据直到数据接收完成;

  本文附带源代码还包括了一个使用 CHttpSocket 实现下载功能的例子工程。注意,所有的调用都是阻塞的,所以最好为一个下载任务创建一个线程 ,否则会导致界面无法响应用户输入。 程序运行界面如下图所示:

直接用socket实现HTTP协议 - FengRalf - 聪明人在说话前总是考虑很久然后什么也不说

该图显示了请求头,回应头以及下载进度。
  当然,要真正实现多任务多线程下载还有很多工作要做。本文仅仅讨论了自己实现下载的一种可能性,希望对读者有所帮助。欢迎来Mail指教


文章来源:http://fengqing888.blog.163.com/blog/static/33011416201171531346915

posted @ 2011-08-15 15:14 FengRalf 阅读(403) | 评论 (0)编辑 收藏
[导入]时间函数 linux

Linux的时间函数

 一、时间相关说明

格林威治时间表示0时区的标准时间。其他时区的时间和此标准时间均有时间差。UTC(Universal Time Coordinated)是世界协调时间,是格林威治时间在互联网中的表示方法

二、标准C语言时间函数

1、time(取得本地目前的时间秒数)

#include<time.h>

time_t time(time_t *t);

函数说明  此函数会返回从公元1970年1月1日的UTC时间从0时0分0秒(Epoch,linux纪元)算起到现在所经过的秒数。如果t 并非空指针的话,此函数也会将返回值存到t指针所指的内存。

返回值  成功则返回秒数,失败则返回((time_t)-1)值,错误原因存于errno中。

time_t 定义为long int

范例  #include<time.h>

mian()

{

long int seconds= time((time_t*)NULL);

printf(“%d\n”,seconds);

}

执行  9.73E+08

2、gmtime(根据本地时间取得目前的UTC时间)

#include<time.h>

struct tm*gmtime(const time_t*timep);

函数说明  gmtime()将参数timep 所指的time_t 结构中的信息转换成真实世界所使用的时间日期表示方法,然后将结果由结构tm返回。

结构tm的定义为

struct tm

{

int tm_sec;

int tm_min;

int tm_hour;

int tm_mday;

int tm_mon;

int tm_year;

int tm_wday;

int tm_yday;

int tm_isdst;

};

int tm_sec 代表目前秒数,正常范围为0-59,但允许至61秒

int tm_min 代表目前分数,范围0-59

int tm_hour 从午夜算起的时数,范围为0-23

int tm_mday 目前月份的日数,范围01-31

int tm_mon 代表目前月份,从一月算起,范围从0-11

int tm_year 从1900 年算起至今的年数

int tm_wday 一星期的日数,从星期一算起,范围为0-6

int tm_yday 从今年1月1日算起至今的天数,范围为0-365

int tm_isdst 日光节约时间的旗标

此函数返回的时间日期未经时区转换,而是UTC时间。

返回值  返回结构tm代表目前UTC 时间

范例  #include <time.h>

main(){

char *wday[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};

time_t timep;

struct tm *p;

time(&timep);

p=gmtime(&timep);

printf(“%d%d%d”,(1900+p->tm_year), (1+p->tm_mon),p->tm_mday);

printf(“%s%d;%d;%d\n”, wday[p->tm_wday], p->tm_hour, p->tm_min, p->tm_sec);

}

执行  2000/10/28 Sat 8:15:38

3、localtime(取得当地目前UTC时间和日期) 

#include<time.h>

struct tm *localtime(const time_t * timep);

函数说明  localtime()将参数timep所指的time_t结构中的信息转换成真实世界所使用的时间日期表示方法,然后将结果由结构tm返回。结构tm的定义请参考gmtime()。此函数返回的时间日期已经转换成当地时区。

返回值  返回结构tm代表目前的当地时间。

范例  #include<time.h>

main(){

char *wday[]={“Sun”,”Mon”,”Tue”,”Wed”,”Thu”,”Fri”,”Sat”};

time_t timep;

struct tm *p;

time(&timep);

p=localtime(&timep); /*取得当地时间*/

printf (“%d%d%d ”, (1900+p->tm_year),( l+p->tm_mon), p->tm_mday);

printf(“%s%d:%d:%d\n”, wday[p->tm_wday],p->tm_hour, p->tm_min, p->tm_sec);

}

执行  2000/10/28 Sat 11:12:22

4、ctime(将时间和日期以字符串格式表示) 

#include<time.h>

char *ctime(const time_t *timep);

函数说明  ctime()将参数timep所指的time_t结构中的信息转换成真实世界所使用的时间日期表示方法,然后将结果以字符串形态返回。此函数已经由时区 转换成当地时间,字符串格式为“Wed Jun 30 21 :49 :08 1993\n”。若再调用相关的时间日期函数,此字符串可能会被破坏。

返回值  返回一字符串表示目前当地的时间日期。

范例  #include<time.h>

main()

{

time_t timep;

time (&timep);

printf(“%s”,ctime(&timep));

}

执行  Sat Oct 28 10 : 12 : 05 2000

5、asctime(将时间和日期以字符串格式表示) 

#include<time.h>

char * asctime(const struct tm * timeptr);

函数说明  asctime()将参数timeptr所指的tm结构中的信息转换成真实世界所使用的时间日期表示方法,然后将结果以字符串形态返回。此函数已经由时区转换成当地时间,字符串格式为:“Wed Jun 30 21:49:08 1993\n”

返回值  若再调用相关的时间日期函数,此字符串可能会被破坏。此函数与ctime不同处在于传入的参数是不同的结构。

附加说明  返回一字符串表示目前当地的时间日期。

范例  #include <time.h>

main()

{

time_t timep;

time (&timep);

printf(“%s”,asctime(gmtime(&timep)));

}

执行  Sat Oct 28 02:10:06 2000

6、mktime(将时间结构数据转换成经过的秒数) 

#include<time.h>

time_t mktime(strcut tm * timeptr);

函数说明  mktime()用来将参数timeptr所指的tm结构数据转换成从公元1970年1月1日0时0分0 秒算起至今的UTC时间所经过的秒数。

返回值  返回经过的秒数。

范例  /* 用time()取得时间(秒数),利用localtime()

转换成struct tm 再利用mktine()将struct tm转换成原来的秒数*/

#include<time.h>

main()

{

time_t timep;

strcut tm *p;

time(&timep);

printf(“time() : %d \n”,timep);

p=localtime(&timep);

timep = mktime(p);

printf(“time()->localtime()->mktime():%d\n”,timep);

}

执行  time():974943297

time()->localtime()->mktime():974943297

设置系统时间

标准C库中只有获取系统时间的API,好像还没有设置系统时间的API,本文将谈谈如何在linuxwindows平台设置系统时间,最后给出一个与平台无关的设置系统时间的封闭函数。

Linux下设置系统时间:

1Linux下设置系统时间的函数有好几个,先来看看最常用的stime()函数,这个函数只能精确到秒。

#define _SVID_SOURCE /*如果你使用的是glib2的话,必须先定义这个宏才能使用*/

#include <time.h>

int stime(time_t *t);

参数说明:

t是以秒为单位的时间值,从GMT197011000秒开始计算。

返回值:

成功返回0,错误返回-1errno错误码,EFAULT表示传递的参数错误,如时间值是无效的值,EPERM表示权限不够,注意只有root用户才有修改系统时间的权限。如果要让普通程序修改系统时间,可以先切换到root用户操作,修改完成后,再切换到普通用户,或者用命令chmod +s给执行文件加上root用户的权限。

2linux是如何管理时间的?

在系统启动时,Linux操作系统将时间从CMOS中读到系统时间变量中,以后修改时间通过修改系统时间实现。为了保持系统时间与CMOS时间的一致性,Linux每隔11分钟会将系统时间写入CMOS,同步时间。从这可以看出,获取系统时间有两个途径,一种是从CMOS中读,一种是从系统中读,但修改时间却只有一种,即修改linux系统中的时间,而修改CMOS中的时间是无效的,因为CMOS中的时间会被定时重写掉。另外还有一点要注意,修改了系统时间并不是马上生效的,假如你修改了系统时间并马上关机,再开机的时候,时间还是原来的,因为修改的时间还没有来得及写入CMOS中。

3.通过settimeofday()函数来设置系统时间,这个函数设置的精度可以精确到微秒。

#include <sys/time.h>

int settimeofday(const struct timeval *tv , const struct timezone *tz);

struct timeval {

    time_t      tv_sec;     /* seconds */

    suseconds_t tv_usec;    /* microseconds */

};

struct timezone {

    int tz_minuteswest;     /* minutes west of Greenwich */

    int tz_dsttime;         /* type of DST correction */

};

tz参数为时区,时区结构中tz_dsttimelinux中不支持,应该置为0,通常将参数tz设置为NULL,表示使用当前系统的时区。该函数是glib中的,但在mingw中没有实现。

该函数返回值与stime()一样,同样也需要root权限。

4.设置CMOS时间,其实它是通过RTCReal-time clock)设备驱动来完成的,你可以用ioctl()函数来设置时间,当然也可以通过操作/dev/rtc设备文件,在此就不详细说明了。

二、windows下设置系统时间

1.设置当前时区的时间

#include <winbase.h>

BOOL SetLocalTime(const SYSTEMTIME* lpSystemTime);

typedef struct _SYSTEMTIME {  // st  

    WORD wYear; 

    WORD wMonth; //月份从1开始

    WORD wDayOfWeek; //SetLocalTime()不使用这个参数

    WORD wDay; 

    WORD wHour; 

    WORD wMinute; 

    WORD wSecond; 

    WORD wMilliseconds; 

} SYSTEMTIME;

函数成功返回非零,失败返回零。注意要求调用进程必需有SE_SYSTEMTIME_NAME权限。

2.另外还有一个函数SetSystemTime(),它的参数与SetLocalTime一样,只不过以UTC时区为基准的。

BOOL SetSystemTime(const SYSTEMTIME* lpSystemTime);

<!--[if !supportLists]-->二、<!--[endif]-->一个封装的设置系统时间的函数

//设置成功返回true,否则返回false

       bool set_local_time(struct tm& t)

{

#ifdef _WIN32

       SYSTEMTIME st;

       memset(&st, 0, sizeof(SYSTEMTIME));

       st.wYear = t.tm_year + 1970; //注意struct tm结构中的年是从1970年开始的计数

       st.wMonth = t.tm_mon + 1; //注意struct tm结构中的月份是从0开始的

       st.wDay = t.tm_mday;

       st.wHour = t.tm_hour;

       st.wMinute = t.tm_min;

       st.wSecond = t.tm_sec;

       if(!SetLocalTime(&st))

              return true;

              else

                     return false;

       #else

              //struct tm结构时间转换成GMT时间time_t

              struct time_t st;

              st = mktime(&t);

              if(st==-1)

                     return false;

              if(!stime(st))

                     return true;

              else

                     return false;

#endif

}

 

三、linux系统时间函数

1、gettimeofday(取得目前的时间) 

#include <sys/time.h>

#include <unistd.h>

int gettimeofday ( struct timeval * tv , struct timezone * tz )

函数说明  gettimeofday()会把目前的时间有tv所指的结构返回,当地时区的信息则放到tz所指的结构中。

timeval结构定义为:

struct timeval{

long tv_sec;   /*秒,也是从linux纪元时间开始的秒数,和用time函数获取的数据一致*/

long tv_usec; /*微秒*/

};

timezone 结构定义为:

struct timezone{

int tz_minuteswest; /*和Greenwich 时间差了多少分钟*/

int tz_dsttime; /*日光节约时间的状态*/

};

上述两个结构都定义在/usr/include/sys/time.h。tz_dsttime 所代表的状态如下

DST_NONE /*不使用*/

DST_USA /*美国*/

DST_AUST /*澳洲*/

DST_WET /*西欧*/

DST_MET /*中欧*/

DST_EET /*东欧*/

DST_CAN /*加拿大*/

DST_GB /*大不列颠*/

DST_RUM /*罗马尼亚*/

DST_TUR /*土耳其*/

DST_AUSTALT /*澳洲(1986年以后)*/

返回值  成功则返回0,失败返回-1,错误代码存于errno。附加说明EFAULT指针tv和tz所指的内存空间超出存取权限。

范例  #include<sys/time.h>

#include<unistd.h>

main(){

struct timeval tv;

struct timezone tz;

gettimeofday (&tv , &tz);

printf(“tv_sec; %d\n”, tv,.tv_sec) ;

printf(“tv_usec; %d\n”,tv.tv_usec);

printf(“tz_minuteswest; %d\n”, tz.tz_minuteswest);

printf(“tz_dsttime, %d\n”,tz.tz_dsttime);

}

执行  tv_sec: 974857339

tv_usec:136996

tz_minuteswest:-540

tz_dsttime:0

 

2、settimeofday(设置目前时间)

#include<sys/time.h>

#include<unistd.h>

int settimeofday ( const struct timeval *tv,const struct timezone *tz);

 

函数说明  settimeofday()会把目前时间设成由tv所指的结构信息,当地时区信息则设成tz所指的结构。详细的说明请参考gettimeofday()。注意,只有root权限才能使用此函数修改时间。

 

返回值  成功则返回0,失败返回-1,错误代码存于errno。

错误代码  EPERM 并非由root权限调用settimeofday(),权限不够。

EINVAL 时区或某个数据是不正确的,无法正确设置时间。

3、clock_gettime(获取指定时钟的时间值)

#include <time.h>

int clock_gettime( clockid_t clock_id,struct timespec * tp );

说明:clock_id指定要获取时间的时钟,根据Posix的指定可以是以下值:

CLOCK_REALTIME

Systemwide realtime clock.

 

CLOCK_MONOTONIC

Represents monotonic time. Cannot be set.

 

CLOCK_PROCESS_CPUTIME_ID

High resolution per-process timer.

 

CLOCK_THREAD_CPUTIME_ID

Thread-specific timer.

 

CLOCK_REALTIME_HR

High resolution version of CLOCK_REALTIME.

 

CLOCK_MONOTONIC_HR

High resolution version of CLOCK_MONOTONIC.

 

struct timespec {

time_t tv_sec;        /* seconds */

long  tv_nsec;       /* nanoseconds 纳秒*/

};

 

4、adjtimex(tune kernel clock)

#include <sys/timex.h>

int adjtimex(struct timex *buf);

说明:

Linux  uses  David L. Mills' clock adjustment algorithm (see RFC 1305).The system call adjtimex() reads and optionally sets adjustment parame-ters  for  this  algorithm.   It  takes a pointer to a timex structure,updates kernel parameters from  field  values,  and  returns  the  same structure  with  current  kernel values.  This structure is declared as follows:

struct timex {

int modes;           /* mode selector */

long offset;         /* time offset (usec) */

long freq;           /* frequency offset (scaled ppm) */

long maxerror;       /* maximum error (usec) */

long esterror;       /* estimated error (usec) */

int status;          /* clock command/status */

long constant;       /* pll time constant */

long precision;      /* clock precision (usec) (read only) */

long tolerance;      /* clock frequency tolerance (ppm) (read only) */

struct timeval time; /* current time (read only) */

long tick;           /* usecs between clock ticks */

};

The modes field determines which parameters, if any, to  set.   It  may contain a bitwise-or combination of zero or more of the following bits:

 

#define ADJ_OFFSET            0x0001 /* time offset */

#define ADJ_FREQUENCY         0x0002 /* frequency offset */

#define ADJ_MAXERROR          0x0004 /* maximum time error */

#define ADJ_ESTERROR          0x0008 /* estimated time error */

#define ADJ_STATUS            0x0010 /* clock status */

#define ADJ_TIMECONST         0x0020 /* pll time constant */

#define ADJ_TICK              0x4000 /* tick value */

#define ADJ_OFFSET_SINGLESHOT 0x8001 /* old-fashioned adjtime() */ 

Ordinary users are restricted to a zero value for mode.  Only the supe-ruser may set any parameters. 

RETURN VALUE

On success, adjtimex() returns the clock state: 

#define TIME_OK   0 /* clock synchronized */

#define TIME_INS  1 /* insert leap second */

#define TIME_DEL  2 /* delete leap second */

#define TIME_OOP  3 /* leap second in progress */

#define TIME_WAIT 4 /* leap second has occurred */

#define TIME_BAD  5 /* clock not synchronized */ 

On failure, adjtimex() returns -1 and sets errno. 

ERRORS

EFAULT

buf does not point to writable memory. 

EINVAL

An attempt is made to set buf.offset to a value outside the range -131071 to +131071, or to set buf.status to a value other than those listed above, or to set buf.tick to a value outside the range 900000/HZ to 1100000/HZ, where HZ is the system  timer interrupt frequency. 

EPERM

buf.mode is non-zero and the caller does not have sufficient privilege.Under Linux the CAP_SYS_TIME capability is required.

CONFORMING TO

adjtimex() is Linux specific and should not be used in programs intended to be portable. See adjtime(3) for a more portable, but less flexible, method of adjusting the system clock.


文章来源:http://fengqing888.blog.163.com/blog/static/330114162011715105727165

posted @ 2011-08-15 10:57 FengRalf 阅读(811) | 评论 (0)编辑 收藏

2011年8月13日

[导入]如何使用man命令

比如要查找ls命令的手册,就输入man ls。
想知道man的具体用法,输入 man man

大家都知道在Unix/Linux中有个man命令,可以查询常用的命令,函数。可是对于我们这样只知道用"man 函数名"来查询的人来说,会遇到很多问题,比如:
      man read,我想看的是ANSI C中stdio的read函数原型和说明,没想到出来的确是BASH命令的说明,这是怎么回事呢?
      原来read本身是man命令的一个参数,这样输入man就会以为你要使用read的功能,而不是查看read函数,那么要怎样查看read函数呢?
       答案是使用:    man 2 read 或者是man 3 read
       中间的数字是什么意思呢?是man的分卷号,原来man分成很多部分,分别是:
1 用户命令, 可由任何人启动的。
2 系统调用, 即由内核提供的函数。
3 例程, 即库函数,比如标准C库libc。
4 设备, 即/dev目录下的特殊文件。
5 文件格式描述, 例如/etc/passwd。
6 游戏, 不用解释啦!
7 杂项, 例如宏命令包、惯例等。
8 系统管理员工具, 只能由root启动。
9 其他(Linux特定的), 用来存放内核例行程序的文档。
n 新文档, 可能要移到更适合的领域。
o 老文档, 可能会在一段期限内保留。
l 本地文档, 与本特定系统有关的。
      要查属于哪一部分的,就用哪一部分的编号在命令之前。
此外,在Ubuntu中是可以安装中文man的,不会的可以GOOGLE下 ......

在系统中,用户可以非常容易的获得系统地帮助和支持,系统发行版本中为几乎每个程序、工具、命令或系统调用编制了使用手册。要想查看某个命令的使用手册页,只要输入man后面跟该命令的名称即可。例如,输入如下命令将显示如图3-7所示的界面。

$ man ls

在此界面中可以查看有关ls命令的详细使用说明。用户可以使用↑、↓和PgDn、PgUp键进行翻阅,按q键退出。

一般来说,命令的使用手册页中会包括如表3-5中所示的组成信息。

表3-5  命令使用手册页中的组成

手册项目

   

Name

命令的名称及简单说明

Synopsis

如何使用这个命令即命令行选项

Description

对这个命令及其选项的解释

Files

这个命令用到的文件清单和它们存放的位置

See Also

有关的使用手册页的清单

Diagnostics

特殊输出情况的说明

Bugs

编程漏洞

Author

命令程序的主要编写者和其他维护人员



文章来源:http://fengqing888.blog.163.com/blog/static/33011416201171354222688

posted @ 2011-08-13 17:42 FengRalf 阅读(375) | 评论 (0)编辑 收藏
仅列出标题  下一页