SRC Language

更新至版本1.1

 SRCSend Recv Cmds)語言主要用於快速編寫網絡測試程序,用戶在SRC源文件裏列出每個命令的每個字段,然後使用SRC編譯器讀取源文件,自動發送或接收命令。如果需要測試的命令比較多,或者有多個相關功能需要系列測試,使用SRC語言能夠大大節省時間和精力,因爲用戶不需要編寫任何測試程序,所有的工作都是寫文本配置文件(SRC源文件),並且可以在以後隨時修改。

此外,SRC源文件與命令文檔結構類似,所以爲命令編寫的SRC測試源文件,可以直接作爲命令解釋文檔使用。甚至SRC源文件擁有比一般命令文檔更多、更準確的信息,例如採用的連接類型、字節序約定、加密協議、HTTP包裝等等,因爲這些都是SRC源代碼裏必須明確指定的信息。

SRC源代碼結構

SRC的源代碼主要包括:變量聲明,函數調用,和命令結構。下面是一個簡單的例子:

 

STR server_ip := "127.0.0.1"    //變量聲明

U16 server_port := 9527

TCP conn(server_ip,server_port)

 

NET_BYTE_ORDER                     //函數調用

 

COMMAND QueryCommand              //命令結構

SEND(conn)

U16 ver := 100

U16 cmd_type := 161

U32 seq := 1234

U32 len

BEGIN(len)

STR file_hash := "http://www.google.com"

STR client_hash := UNHEX("1A2B3C4D5E6F")

STR peer_id := "ABCDEF1234567890"

END COMMAND

 

上面的SRC代碼定義了一個名爲“QueryCommand”的命令結構,並準備發送給本機的9531端口。

數據類型

SRC語言支持的基本數據類型有:

分類

關鍵字

字節數

意義

數值類型

U8

1

無符號8位整數

S8

1

有符號8位整數

U16

2

無符號16位整數

S16

2

有符號16位整數

U32

4

無符號32位整數

S32

4

有符號32位整數

U64

8

無符號64位整數

S64

8

有符號64位整數

字符串類型

STR

可變

字符串

RAW

可變

字符串

網絡連接類型

TCP

N/A

TCP連接

UDP

N/A

UDP連接

1  基本數據類型

數值類型的變量,編碼和解碼時直接寫入和讀取真正的數據。

STR類型的變量,編碼時首先寫入U32類型的長度字段,然後寫入真正的數據;在解碼時,STR類型的變量首先讀取U32類型的長度,然後讀取真正的數據;

RAW類型的變量,編碼時直接寫入真正的數據;在解碼時,RAW類型的變量直接讀取真正的數據,但是必須和其他條件配合才能確定讀取的結束位置。

TCPUDP屬於網絡連接類型,不能被編碼或解碼,

 

函數調用

SRC語言裏,函數調用的格式爲:

FUNCTION ( arg_list )

FUNCTION

其中,FUNCTION可以是任意內置函數,或者是任意數據類型關鍵字。arg_list是用‘,’分隔的參數列表,可以爲空。對於內置函數,當參數列表爲空的時候,可以省略‘(’和‘)’。

 

內置函數

SRC語言提供瞭如下的內置函數:

l  HBOHOST_BYTE_ORDER

參數:無

意義:設置以本地字節序編碼或解碼

說明:由於HBO函數沒有參數,調用時採用下面2種形式均可:

HBO

HBO()

HOST_BYTE_ORDER

HOST_BYTE_ORDER()

 

l  NBONET_BYTE_ORDER

參數:無

意義:設置以網絡字節序編碼或解碼

說明:由於NBO函數沒有參數,調用時採用下面2種形式均可:

NBO

NBO()

NET_BYTE_ORDER

NET_BYTE_ORDER()

在默認情況下,SRC編譯器採用網絡字節序進行編碼和解碼。

 

l  HEX

參數:字符串

意義:將參數字符串的每個字符以16進製表示生成新字符串,作爲函數的返回值

說明:採用如下方式調用:

STR hex_1 = HEX(“abc”)    // hex_1 = “616263”

 

l  UNHEX

參數:字符串

意義:將參數字符串的每2個字符作爲16進制數值,生成新字符串,作爲函數的返回值

說明:要求參數字符串爲連續的16進制字符(0-9A-Fa-f),例如:

STR origin = UNHEX(“616263”)   // origin = “abc”

 

l  SEND

參數:若干連接變量(TCPUDP

意義:將命令發送給指定的連接

說明:如果SEND函數沒有參數,那麼編譯器會選擇整個源文件裏定義的第一個連接變量作爲參數。SEND函數的參數個數沒有限制,如果參數裏有重複的連接變量,那麼同一個命令會多次發送給這個連接。調用示例:

SEND        // 自動選擇第一個連接變量作爲參數

SEND()

SEND(conn1,conn2,…)

 

l  RECV

參數:若干連接變量(TCPUDP

意義:從指定的連接接收命令

說明:如果RECV函數沒有參數,那麼編譯器會選擇整個源文件裏定義的第一個連接變量作爲參數。雖然從語法上,RECV函數的參數個數沒有限制,但運行時只從RECV函數的第一個參數接收命令,這是目前編譯器的實現限制。調用示例:

RECV        // 自動選擇第一個連接變量作爲參數

RECV()

RECV(conn1,conn2,…)   // 運行時只從conn1接收命令

 

l  BEGIN

參數:1個或以上的變量名

意義:爲計算數據段長度的變量指定起始偏移位置

說明:在命令裏總有一些字段表示某個數據段的長度。在數據段開始的地方,調用BEGIN函數,並傳入記錄該數據段長度的變量的名字。

BEGIN函數的參數必須是變量名,並且這些變量必須是數值類型的(UxxSxx)。調用示例:

U32 body_len

BEGIN(body_len)

 

l  END

參數:1個或以上的變量名

意義:爲計算數據段長度的變量指定結束偏移位置

說明:在數據段結束的地方,調用END函數,並傳入記錄該數據段長度的變量的名字。END函數應該與BEGIN函數成對出現,並且END函數的位置應在後面。在一個命令結構結束的時候,如果存在調用了BEGIN函數卻沒有調用END函數的變量,編譯器會自動爲其調用END函數,位置就是整個命令的結尾。

END函數的參數必須是變量名,並且這些變量必須是數值類型的(UxxSxx)。調用示例:

U32 body_len

BEGIN(body_len)

……  // 任意字段

END(body_len)

 

l  FUNFUNCTION

參數:自定義函數名字 + 長度數值

意義:對命令數據調用指定的用戶自定義函數

說明:有些命令除了寫入所有字段,還需要進行一些特殊處理,比如加密、計算校驗碼等等;同樣,有些命令除了讀取所有字段,需要進行上述操作的逆處理。SRC語言沒有從語法上支持這些複雜的操作,但是允許用戶對命令數據進行自定義的操作,方式就是通過FUN函數調用。調用示例:

FUN(my_encrypt_fun)

FUN(my_decrypt_fun,30)   //保證後續至少有30字節數據的前提下調用指定函數

 

l  IP NBO

參數:1個字符串或1個數值

意義:把參數字符串表示的IPv4地址轉化爲網絡字節序U32數值;或者將網絡字節序U32數值轉化成爲IPv4字符串

說明:注意這裏是2個關鍵字組合起來,表示一個函數。採用如下方式調用:

STR ip_str = IP NBO(0x505AA8C0)       // ip_str = “192.168.90.80”

STR ip_val = IP NBO(“192.168.90.80”) // ip_val = 0x505AA8C0

 

l  IP HBO

參數:1個字符串或1個數值

意義:把參數字符串表示的IPv4地址轉化爲本地字節序U32數值;或者將本地字節序U32數值轉化成爲IPv4字符串

說明:同上面一樣,這裏是2個關鍵字組合起來,表示一個函數。採用如下方式調用:

STR ip_str = IP HBO(0xC0A85A50)       // ip_str = “192.168.90.80”

U32 ip_val = IP HBO(“192.168.90.80”) // ip_val = 0xC0A85A50

 

l  PRINT

參數:1個或以上的可打印變量

意義:在標準輸出打印指定的內容

說明:可用於在代碼任何地方,打印出任何信息,包括調試信息,提示信息,等等。PRINT函數要求至少有一個參數,沒有上限。目前,所有SRC語言的基本類型都是可打印的。調用示例:

U32 val = 100

STR str = “Hello”

TCP conn(“127.0.0.1”,9531)

PRINT(“val = “,val)

PRINT(“str = “,str)

PRINT(“conn = “,conn)

會在標準輸出上打印:

val = 100

str = Hello

conn = (3,127.0.0.1:9531)    //打印格式爲 (fd , IP : Port)

 

l  BEGIN ARRAY

參數:0個或1個的數值變量

意義:指定一個數組的起始位置,參數數值表示元素個數

說明:有些命令並非只是簡單字段的組合,而是有內部的邏輯結構,甚至有一些複雜結構的數組。“BEGIN ARRAY”函數用於定義這種結構體數組的起始位置。

調用示例:

BEGIN ARRAY(3)          //指定數組起始位置,並指定元素個數爲3

U32 val = 100

STR str = “abc”

END ARRAY                //數組結構結束,每個元素包含U32STR兩個字段

該函數只能出現在命令結構體內。

如果在發送命令裏:

1.       如果函數沒有參數,SRC編譯器報告“數組長度未知”錯誤;

2.       如果函數有參數,SRC編譯器把元素的每個字段依次編碼,並重復參數指定的次數。

例如上面的代碼,由於指定了元素個數爲3,編譯器會把:

編碼U32變量val

編碼STR變量str

重複做3次。這就相當於編碼了3個結構體,每個結構體包括U32STR兩個字段。

如果在接收命令裏:

1.       如果函數沒有參數,SRC編譯器會先讀取U32元素個數字段,然後依次讀取每個元素的每個字段;

2.       如果函數有參數,SRC編譯器會假定元素個數爲參數數值,直接依次讀取每個元素的每個字段。

值得注意的是,“BEGIN ARRAY”函數可以嵌套調用,即在一個數組結構體內部,可以定義另一個數組結構體,這樣就允許定義任意複雜的命令,例如:

BEGIN ARRAY      //第一層數組結構體

  U32 val_1

  BEGIN ARRAY    //第二層數組結構體

    U8 val_2

    BEGIN ARRAY  //第三層數組結構體

      STR str_3

      STR id_3

    END ARRAY    //第三層數組結構體結束

    U64 sz_2

  END ARRAY      //第二層數組結構體結束

  STR str_1

END ARRAY        //第一層數組結構體結束

實際中可能很難找到如此複雜的命令,但是有些命令的確會用到第二層數組結構體。

 

l  END ARRAY

參數:無

意義:指定一個數組的結束位置

說明:“END ARRAY”函數必須與BEGIN ARRAY”函數成對出現。函數的使用請見上面的介紹。

 

構造函數

SRC語言裏,每一種數據類型都對應有若干個構造函數,用於初始化相應的變量。下面是各種數據類型的構造函數的介紹:

l  U8S8U16S16U32S32U64S64

參數:0個或1個數值或變量名

意義:用參數值或0初始化對應類型的變量

說明:如果參數列表爲空,則用0初始化變量。調用示例:

U32 v1 = U32(100)

U32 v2 = U32(v1)

U8 v3 = U8()       //使用0初始化變量

數值類型的變量可以直接相互賦值,但是當出現溢出或者符號不匹配時,SRC編譯器會報告一個運行時錯誤,此時用戶應該確認轉化的正確意義。

 

l  STRRAW

參數:0個或1個字符串或變量名

意義:用參數字符串初始化對應類型的變量

說明:如果參數列表爲空,則用空字符串初始化變量。調用示例:

STR s1 = STR(“abc”)

RAW v2 = RAW(s1)

RAW v3 = RAW()       //默認使用空字符串初始化變量

STRRAW類型的變量,可以直接相互賦值。

 

l  TCPUDP

參數:以下幾種組合都是可以的:

s  1個相同類型的連接對象

s  字符串(IP地址)+ 字符串(端口)+ 數值(超時,可省略)

s  字符串(IP地址)+ 數值(端口)+ 數值(超時,可省略)

意義:建立新連接,或指向一個已有的連接

說明:如果參數是另一個連接對象,那麼只是複製了指向連接的指針,而沒有建立新的連接;其他情況下會建立一個新的連接。“超時”參數暫時沒有任何作用,並且可以省略,因爲當前的SRC編譯器採用阻塞模式發送和接收數據。

調用示例:

UDP(“127.0.0.1”,9527)

TCP tcp1 = TCP(“127.0.0.1”,”9527”)

TCP tcp2 = TCP(tcp1)   //只是複製了連接指針,沒有建立新的連接

TCPUDP變量之間不能相互轉化,並且也不能參與命令編碼與解碼,所以無論是構造函數,還是變量聲明,都只能出現在命令結構之外,即全局空間裏。

整個SRC源文件裏,最先建立的連接(無論是通過變量聲明,還是構造函數),會作爲默認連接,如果調用SENDRECV函數而沒有傳遞參數,SRC編譯器會選擇默認連接作爲參數。

 

變量聲明

變量聲明是SRC語言裏最重要、最複雜的語句,也是使用最多的語句。SRC語言的變量聲明分爲普通聲明和自由變量聲明。首先介紹普通聲明:

數組變量聲明

數組變量的聲明格式爲:

TYPE [] name

TYPE [ expression ] name

其中,TYPE是數據類型關鍵字;expression是任意可求值的表達式,並且是數值類型。例如:

U32 [] u32_array;

STR [] str_array;

U8[12] char_array_size_12;

但是以下類型不能聲明爲數組:

s   RAW

s   TCP

s   UDP

數組類型的變量不能被編碼,因爲數組聲明無法給元素賦初值。在解碼時,沒有指定長度的數組變量,會先讀取U32類型的元素個數字段,然後依次讀取每個元素;指定了長度的數組變量,直接讀取每個元素。

數組變量聲明只允許出現在接收命令結構裏。

上面第一種聲明方式通過讀取到的命令數據內容來決定元素的個數,第二種方式指定了數組的元素個數。其實這2種方式在某些情況下是等價的,例如:

STR[] str_array   //先讀取U32元素個數,再讀取每個元素

等價於

U32 array_sz      //先讀取U32元素個數

STR[array_sz] str_array  //再讀取每個元素

 

常量聲明

SRC語言裏,常量是指在聲明的時候可以立刻求值,並且在以後都不會改變的對象,相當於C++裏的const常量。常量的聲明方式如下:

TYPE name := expression

TYPE name :( arg_list )

其中,expression表示任何可求值的表達式,而arg_list表示用‘,’分隔的參數列表,可以爲空。例如:

U32 ver := 100       //定義值爲100U32常量

U32 ver:(100)        //與上面等價

TCP conn := TCP(“127.0.0.1”,9527) //定義一個TCP常量,連接本機的9527端口

TCP conn:(“127.0.0.1”,9527)         //與上面等價

TCP conn1 := conn   //定義另一個TCP常量conn1,與conn表示同一個連接

TCP conn1:(conn)    //與上面等價

常量聲明只能出現在全局空間或發送命令結構裏。

 

普通變量聲明

SRC語言裏,普通變量是指在聲明的時候無法求值,或者求出的不一定是最終值的對象。普通變量的聲明方式如下:

TYPE name

TYPE name = expression

TYPE name ( arg_list )

其中expressionarg_list的意義與常量的相同。例如:

U32 body_len      //定義初值爲0U32變量,可能在後面被改變

U32 body_len = 0 //與上面等價

U32 body_len(0)   //與上面等價

普通變量聲明可以出現在任何地方。

對於TCPUDP連接類型,普通變量聲明和常量聲明是等價的,因爲連接總是會在變量聲明的地方開始建立,並且無法改變變量所代表的連接對象。

對於STRRAW類型,因爲除了在普通變量聲明的時候賦值,沒有其他方法改變值,所以普通變量和常量的聲明也是等價的。

 

斷言變量聲明

斷言變量聲明是SRC語言引入的新語法,用於在讀取命令字段的同時,檢查字段值的有效性。在接收命令裏,爲了儘早發現錯誤的數據,可以爲一些字段加上限制條件,例如版本號應該大於或等於100,數據包長度應該小於32K字節,等等。這些限制條件可以通過斷言變量方便的實現。斷言變量的聲明方式如下:

TYPE name OP expression

其中,OP是下列判斷操作符之一:

s   <

 

s   >

 

s   <=

s   >=

s   ==

s   !=

expression的意義與前面的相同。例如:

U32 ver >= 100      //變量ver的值必須大於或等於100

U32 body_len < 32K //變量body_len的值必須小於32×1024

RAW str == “HTTP header”  //字符串str必須等於“HTTP header

斷言變量的聲明只能出現在接收命令裏,因爲在其他地方進行斷言,本身就是沒有意義的。

如果斷言返回值爲真,SRC編譯器繼續進行後面的操作;如果斷言返回值爲假,SRC編譯器會報告錯誤,並終止操作。

 

流操作變量聲明

流操作變量是SRC語言的又一特色,用於字符串與數值類型變量之間的相互轉化。流操作變量有2種:流輸出變量,流輸入變量。

l  流輸出變量聲明

流輸出變量聲明用於把其他類型的值,轉化成字符串類型的變量,聲明方式如下:

STRING name << expression

其中,STRING表示STRRAWexpression是任意可求值的表達式,並且返回值能夠轉化成字符串。實際上,除了TCPUDP連接類型,SRC語言支持的其他類型都可以轉化成字符串。使用示例:

U32 value = 100

STR str << value     //str = “100”

流輸出變量聲明只能出現在發送命令裏。

 

l  流輸入變量聲明

流輸入變量聲明能把字符串轉化成數值類型,聲明方式如下:

STRING name >> expression

STRING name >> TYPE

其中,STRING表示STRRAWexpression是任意可求值的表達式,並且返回值必須是數值類型;TYPE表示任意數值類型關鍵字(UxxSxx)。使用示例:

DEF U32 value

STR str >> value     //str字符串轉化成U32值,賦給value變量

STR str >> U32       //str字符串轉化成U32

流輸入變量聲明只能出現在接收命令裏。

 

自由變量聲明

只要在普通聲明的前面加上“DEF”或“DEFINE”關鍵字,就是自由變量的聲明。

在命令結構體內,使用普通方式定義的任意變量,都會作爲該命令的字段,並需要進行編碼或解碼。而自由變量則不作爲命令的字段,也不參與編碼或解碼,但是仍像普通變量那樣求值。自由變量在某些場合下有不可替代的作用,例如:

DEF U32 def_total_len          // 使用自由變量計算整個數據包的長度

BEGIN(def_total_len)

……     //命令頭的字段

U32 total_len = def_total_len // 實際編碼的是total_len字段

……     //命令體的字段

END(def_total_len)

上例中,普通變量total_len需要計算整個數據包的長度,這就需要在聲明total_len之前調用BEGIN(total_len),而在函數內使用未定義的變量是SRC語言所不允許的,所以需要使用自由變量def_total_len完成計算任務,最後將值賦給普通變量total_len,並最終編碼進數據包。

 

斷言表達式

斷言表達式用於在接收命令裏判斷數據的合理性,它比斷言變量聲明更好的地方在於:可以隨時隨地進行判斷,不一定非在變量定義的時候。

SRC語言的斷言表達式格式如下:

OP1 expression

expression OP2 expression

其中,OP1代表一元判斷操作符,目前支持的有:

s   !

OP2代表二元判斷操作符,目前支持:

s   <

 

s   >

 

s   <=

s   >=

s   ==

s   !=

expression的意義與前面的相同,不過要求返回值類型可以進行相應的判斷操作。具體來說就是,對於一元操作符“!”,要求expression的返回值是數值類型;對於二元操作符,要求左右expression的返回值要麼都是數值類型,要麼都是字符串類型。例如:

U32 ver

ver >= 100   //二元判斷操作符

!ver          //一元判斷操作

STR str

str == “abc”

 

命令結構

SRC語言主要是用來定義各種各樣的命令結構,而SRC源文件一般就是若干個命令結構的集合。

命令結構的定義通過“CMD”或“COMMAND”關鍵字,格式如下:

CMD CmdName    //命令結構開始,CmdName是命令的名字,可以爲空

……    //任意字段

END CMD         //命令結構結束

命令的名字CmdName可以爲空,但是不允許與其他全局變量重名,不同的命令也不允許使用相同的名字。

命令結構有2種類型:發送命令和接收命令。

 

發送命令

發送命令的標誌,是在所有命令字段聲明之前,有SEND函數調用,例如:

CMD QueryCommand

  SEND

……    //命令的其他字段

END CMD

SEND函數可以被多次調用,也可以傳遞任意個數的參數,SRC編譯器會自動把命令數據發送給SEND函數的每個參數,無論是否有重複。

在發送命令裏不允許出現的語句包括:

s   TCPUDP類型的變量聲明和構造函數

s   數組變量聲明

s   斷言變量聲明

s   流輸入變量聲明

s   RECV函數調用

s   斷言表達式

s   無參數的BEGIN ARRAY函數

下面是一個簡單的發送命令的示例:

 

COMMAND QueryCommand        //命令名字爲“QueryCommand

SEND                         //在所有字段聲明之前調用SEND函數

U16 ver := 100             //對於可以立即求值的字段,請使用常量聲明

U16 cmd_type := 161

U32 seq := 1234

U32 len                      //對於需要延後求值的字段,請使用普通變量聲明

BEGIN(len)                  //調用BEGIN函數

STR file_hash := "http://www.google.com"

STR client_hash := UNHEX("1A2B3C4D5E6F")

STR peer_id := "ABCDEF1234567890"

END COMMAND                   //命令結束時,自動爲len字段調用END函數

 

這個命令只是簡單的把每個字段打包,最後發送出去。

有一些命令,還需要加上HTTP頭,而HTTP頭裏有一個“Content-Length:”字段,表示HTTP數據體的長度,爲了正確填寫這個字段,需要使用自由變量和流輸出變量:

 

CMD QueryCommand SEND       //SEND函數還可以寫在這個位置

RAW http1 := "POST http://127.0.0.1:12345/ HTTP/1.1/r/n/

Content-Length: "          //使用轉義字符/’,將較長的字符串分行表示

DEF U32 pack_len           //使用自由變量記錄命令包的總長度

RAW pack_len_str << pack_len  //pack_len流輸出到字符串

RAW http2 := "/r/nContent-Type: application/octet-stream/r/n/

Connection:Close/r/n/r/n"

BEGIN(pack_len)             //從此處開始計算數據包長度

……                             //其他字段與上例相同

END CMD  //QueryCommand      //命令結束時,自動爲pack_len調用END函數

 

現在,這個發送命令加入了HTTP頭,通過SRC編譯器的處理,最後發送出去的會是如下數據:

 

0000h: 50 4F 53 54 20 68 74 74 70 3A 2F 2F 31 32 37 2E ; POST http://127.

0010h: 30 2E 30 2E 31 3A 31 32 33 34 35 2F 20 48 54 54 ; 0.0.1:12345/ HTT

0020h: 50 2F 31 2E 31 0D 0A 43 6F 6E 74 65 6E 74 2D 4C ; P/1.1..Content-L

0030h: 65 6E 67 74 68 3A 20 35 36 0D 0A 43 6F 6E 74 65 ; ength: 56..Conte

0040h: 6E 74 2D 54 79 70 65 3A 20 61 70 70 6C 69 63 61 ; nt-Type: applica

0050h: 74 69 6F 6E 2F 6F 63 74 65 74 2D 73 74 72 65 61 ; tion/octet-strea

0060h: 6D 0D 0A 43 6F 6E 6E 65 63 74 69 6F 6E 3A 20 43 ; m..Connection: C

0070h: 6C 6F 73 65 0D 0A 0D 0A 00 64 00 A1 00 00 04 D2 ; lose.....d......

0080h: 00 00 00 2C 00 00 00 14 68 74 74 70 3A 2F 2F 77 ; ...,....http://w

0090h: 77 77 2E 62 61 69 64 75 2E 63 6F 6D 00 00 00 06 ; ww.baidu.com....

00a0h: 1A 2B 3C 4D 5E 6F 00 00 00 06 41 42 43 44 45 46 ; .+<M^o....ABCDEF

 

可以看到,HTTP數據體的長度爲“56”,被正確的寫入了HTTP頭信息裏。

除了加HTTP頭信息,還可以對命令進行更加複雜的處理,例如加密解密,計算校驗和等等,這些操作可以通過FUN函數來實現,具體請參考“Using SRC Language”。

 

接收命令

接收命令的標誌,是在所有命令字段聲明之前,有RECV函數調用,例如:

CMD RespCommand

  RECV

……    //命令的其他字段

END CMD

RECV函數可以被多次調用,也可以傳遞任意個數的參數,但是由於實現限制,目前SRC編譯器只會從第一個RECV調用的第一個參數接收數據。

在接收命令裏不允許出現的語句包括:

s   TCPUDP類型的變量聲明和構造函數

s   常量聲明

s   流輸出變量聲明

s   SEND函數調用

下面是一個簡單的接收命令的示例:

CMD RespCommand RECV    //RECV函數還可以寫在這個位置

U16 ver >= 100

U16 cmd_type == 162

U32 seq

U32 len < 32K           //32K = 32×1024 = 32768

U8  result

!result

STR fileHash_ == "http://www.baidu.com";

STR clientHash_;

STR[] peerId_;       //array

END CMD

 

這個接收命令只需解碼每個字段即可,但實際中有些命令會使用HTTP頭回復,例如上面帶HTTP頭的發送命令的回覆。爲了正確的接收HTTP頭信息,需要對RAW類型的變量使用斷言聲明和流輸入聲明,示例如下:

 

CMD RespCommand RECV

RAW http1 == "HTTP/1.1 200 OK/r/nContent-Length: "

                              //使用“==斷言聲明,既判斷內容的正確性,又提示RAW

//字符串的長度

RAW pack_len_str >> U32  //使用流輸入聲明,提示RAW字符串的內容

RAW http2 == "/r/nContent-Type: Application/octet-stream/

/r/nConnection: Close/r/n/r/n"

……                           //其他字段與上例相同

END CMD

 

在接收命令裏讀取RAW字符串字段的最大問題,是無法知道讀取操作的結束位置,因爲RAW字符串沒有長度字段。所以必須與其他條件配置,例如上面的“==”斷言,限制字符串的內容,同時也限制了RAW字符串的長度;而“>>”流輸入操作符,可以限制字符串的內容必須是數字字符“0-9”,當讀取到其他字符的時候,SRC編譯器就知道讀取結束了。

 

其他語法

下面的內容介紹了SRC語言裏比較基礎的一些語法。

 

語法常量

SRC語言的語法常量包括數值常量和字符串常量。數值常量的表達方式遵循C++語法,例如:

 

S32 int_v := 10              //10”表示整型常量10

S32 long_v := 100L          //100L”表示長整型常量100

S64 long_long_v := 1000LL  //1000LL”表示64位長整型常量1000

S64 i64_v := 1000i64        //同上

U32 uint_v := 10U            //10U”表示無符號整型常量10

U32 long_v := 100UL          //100UL”表示無符號長整型常量100

U64 long_long_v := 1000ULL  //1000ULL”表示64位無符號長整型常量1000

S8 char_v := ‘a’              //’a’”表示字符‘a’的ASCII碼值

 

關於數值常量表示語法的詳細信息,請參考C++語言的語法說明。

字符串常量的表達方式同樣遵循C++語法,例如:

 

STR str_v := “abc”              //使用引號表示字符串常量“abc

STR long_str_v := “this is a very long/

string that needs return new line”   //使用轉義字符‘/’使字符串換行

STR odd_str_v := “O/rD/aD/tS/032T/xaeR”

  //這也是合法的字符串常量,不信用C++試試!

 

關於字符串常量表示語法的詳細信息,請參考C++語言的語法說明。

目前SRC語言不支持寬字符和字符串,即以“L”前導表示的字符和字符串。在C++語言裏寬字符的類型是wchar_t,在SRC語言裏沒有對應的類型。

 

註釋

SRC語言的註釋以“#”或“//”開始,到行尾結束,可以與有效代碼同行,例如:

# This is shell style comments

//This is C++ style comments

STR str_v    //comments after statement

C++語言裏,使用“//”的註釋可以通過轉義字符‘/’延伸到下一行,但是在SRC語言裏,這是不允許的,即註釋裏的‘/’字符沒有轉行的意義。

 

語句分隔符

語句分隔符是指一條完整語句的結束標誌,例如C++語言裏的‘;’字符。在SRC語言裏,‘;’字符和換行符都可以作爲語句分隔符,例如下面的寫法都是合法的:

U32 len ; BEGIN(len)   //使用‘;’分隔語句

STR cid                   //使用換行符分割語句

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章