v0.25.0版本使用了v1.9.0版本的zengl语言库,在配置文件中增加了backlog及timezone的配置,此外,在内建模块中增加了bltSetTimeZone的模块函数。
zenglServer源代码的相关地址:https://github.com/zenglong/zenglServer 当前版本对应的tag标签为:v0.25.0
v0.25.0版本使用了v1.9.0版本的zengl语言库,在配置文件中增加了backlog及timezone的配置,此外,在内建模块中增加了bltSetTimeZone的模块函数。
使用v1.9.0版本的zengl语言库,test_self.zl和test_def.zl测试脚本:
当前版本使用了v1.9.0版本的zengl语言库中:
[root@localhost zenglServer]# ./zenglServer -v zenglServer version: v0.25.0 zengl language version: v1.9.0 [root@localhost zenglServer]#
1.9.0版本的zengl语言增加了self的特殊类名,可以在class类结构中使用self来表示当前所在类的类名。为了测试self特殊类名,当前版本在 my_webroot/v0_25_0/ 目录中增加了test_self.zl的测试脚本:
use builtin; class Test act; arg; fun Do(act, arg, obj) self obj; obj.act = act; obj.arg = arg; if(act == 'play') self.play(arg); else self.other(arg); endif self.Print(obj); endfun fun play(game) print 'play: ' + game; endfun fun other(str) print 'other: ' + str; endfun fun Print(obj) self obj; print 'obj.act: ' + obj.act; print 'obj.arg: ' + obj.arg; endfun endclass Test test; test = bltArray(); Test.Do('play', 'football', test); Test.Do('hello', 'worlds', test); Test.Print(test);
上面脚本在Test类结构中,就使用了self来表示Test类名。之前的zengl版本需要使用Test.play这样的语法来调用类方法,1.9.0版本开始则可以使用self.play这样的语法来调用当前类中的方法。此外,之前版本只能使用Test obj;这样的语法来声明类变量,1.9.0版本开始可以使用self obj这样的语法用当前类来声明变量。
上面的test_self.zl脚本在命令行中的执行结果如下:
[root@localhost zenglServer]# ./zenglServer -r /v0_25_0/test_self.zl play: football obj.act: play obj.arg: football other: worlds obj.act: hello obj.arg: worlds obj.act: hello obj.arg: worlds [root@localhost zenglServer]#
此外,1.9.0版本的zengl语言库还增加了zenglApi_SetDefLookupHandle和zenglApi_SetDefLookupResult接口,zenglServer可以使用这些接口来设置预定义的宏值,当前版本在内建模块和openssl模块中就使用了这些接口来设置预定义的宏值,例如,在module_builtin.c的C源文件中,就定义了和内建模块相关的预定义宏值的查询函数:
/** * 內建模块的def宏值查询函数,该查询函数会根据查询名称返回对应的宏值 * 例如:def TRUE ___BUILTIN_TRUE___; 这个语句,就会调用下面这个函数,并将___BUILTIN_TRUE___作为查询名称传递给该函数, * 函数在经过查询后,就会设置整数1作为TRUE的宏值,因此这个语句等效于 def TRUE 1; */ int module_builtin_def_lookup_handle(ZL_EXP_VOID * VM_ARG, ZL_EXP_CHAR * defValName) { char tmpstr[20]; int retval = 1; if(strcmp(defValName, "___BUILTIN_TRUE___") == 0) // 用于脚本中定义TRUE的宏值 { retval = zenglApi_SetDefLookupResult(VM_ARG, ZL_EXP_FAT_INT, "1"); } else if(strcmp(defValName, "___BUILTIN_FALSE___") == 0) // 用于脚本中定义FALSE的宏值 { retval = zenglApi_SetDefLookupResult(VM_ARG, ZL_EXP_FAT_INT, "0"); } else if(strcmp(defValName, "___BUILTIN_NULL___") == 0) // 用于脚本中定义NULL的宏值 { retval = zenglApi_SetDefLookupResult(VM_ARG, ZL_EXP_FAT_INT, "0"); } else if(strcmp(defValName, "___BUILTIN_WRITE_FILE_MODE_WRITE___") == 0) // 用于在脚本中定义bltWriteFile模块函数写入模式的宏值 { snprintf(tmpstr, 20, "%d", WRITE_FILE_MODE_WRITE); retval = zenglApi_SetDefLookupResult(VM_ARG, ZL_EXP_FAT_INT, tmpstr); } else if(strcmp(defValName, "___BUILTIN_WRITE_FILE_MODE_APPEND___") == 0) // 用于在脚本中定义bltWriteFile模块函数追加模式的宏值 { snprintf(tmpstr, 20, "%d", WRITE_FILE_MODE_APPEND); retval = zenglApi_SetDefLookupResult(VM_ARG, ZL_EXP_FAT_INT, tmpstr); } return !retval; }
在module_openssl.c的C源文件中定义了和openssl模块相关的预定义宏值的查询函数:
/** * openssl模块的def宏值查询函数,该查询函数会根据查询名称返回对应的宏值 * 例如:def RSA_SIGN_SHA ___OPENSSL_NID_sha___; 这个语句,就会调用下面这个函数,并将___OPENSSL_NID_sha___作为查询名称传递给该函数, * 函数在经过查询后,就会设置整数0作为RSA_SIGN_SHA的宏值,因此这个语句等效于 def RSA_SIGN_SHA 0; */ int module_openssl_def_lookup_handle(ZL_EXP_VOID * VM_ARG, ZL_EXP_CHAR * defValName) { int retval = 1; if(strcmp(defValName, "___OPENSSL_NID_sha___") == 0) { retval = zenglApi_SetDefLookupResult(VM_ARG, ZL_EXP_FAT_INT, "0"); } else if(strcmp(defValName, "___OPENSSL_NID_sha1___") == 0) { retval = zenglApi_SetDefLookupResult(VM_ARG, ZL_EXP_FAT_INT, "1"); } else if(strcmp(defValName, "___OPENSSL_NID_ripemd160___") == 0) { retval = zenglApi_SetDefLookupResult(VM_ARG, ZL_EXP_FAT_INT, "2"); } else if(strcmp(defValName, "___OPENSSL_NID_md5___") == 0) { retval = zenglApi_SetDefLookupResult(VM_ARG, ZL_EXP_FAT_INT, "3"); } else if(strcmp(defValName, "___OPENSSL_NID_md5_sha1___") == 0) { retval = zenglApi_SetDefLookupResult(VM_ARG, ZL_EXP_FAT_INT, "4"); } else if(strcmp(defValName, "___OPENSSL_NID_sha256___") == 0) { retval = zenglApi_SetDefLookupResult(VM_ARG, ZL_EXP_FAT_INT, "5"); } else if(strcmp(defValName, "___OPENSSL_NID_sha256WithRSAEncryption___") == 0) { retval = zenglApi_SetDefLookupResult(VM_ARG, ZL_EXP_FAT_INT, "6"); } else if(strcmp(defValName, "___OPENSSL_NID_sha512___") == 0) { retval = zenglApi_SetDefLookupResult(VM_ARG, ZL_EXP_FAT_INT, "7"); } else if(strcmp(defValName, "___OPENSSL_NID_sha512WithRSAEncryption___") == 0) { retval = zenglApi_SetDefLookupResult(VM_ARG, ZL_EXP_FAT_INT, "8"); } else if(strcmp(defValName, "___OPENSSL_RSA_PKCS1_PADDING___") == 0) { retval = zenglApi_SetDefLookupResult(VM_ARG, ZL_EXP_FAT_INT, "0"); } else if(strcmp(defValName, "___OPENSSL_RSA_PKCS1_OAEP_PADDING___") == 0) { retval = zenglApi_SetDefLookupResult(VM_ARG, ZL_EXP_FAT_INT, "1"); } else if(strcmp(defValName, "___OPENSSL_RSA_SSLV23_PADDING___") == 0) { retval = zenglApi_SetDefLookupResult(VM_ARG, ZL_EXP_FAT_INT, "2"); } else if(strcmp(defValName, "___OPENSSL_RSA_NO_PADDING___") == 0) { retval = zenglApi_SetDefLookupResult(VM_ARG, ZL_EXP_FAT_INT, "3"); } else if(strcmp(defValName, "___OPENSSL_RSA_PUBLIC___") == 0) { retval = zenglApi_SetDefLookupResult(VM_ARG, ZL_EXP_FAT_INT, "1"); } else if(strcmp(defValName, "___OPENSSL_RSA_PRIVATE___") == 0) { retval = zenglApi_SetDefLookupResult(VM_ARG, ZL_EXP_FAT_INT, "0"); } else if(strcmp(defValName, "___OPENSSL_RSA_USE_EVP___") == 0) { retval = zenglApi_SetDefLookupResult(VM_ARG, ZL_EXP_FAT_INT, "1"); } return !retval; }
使用预定义宏值的好处在于,当底层预定义宏值对应的具体的值发生改变时,不需要再调整脚本中的代码了。当前版本在 my_webroot/v0_25_0/ 目录中增加了test_def.zl的测试脚本:
use builtin; def TRUE ___BUILTIN_TRUE___; def FALSE ___BUILTIN_FALSE___; def WRITE_MODE ___BUILTIN_WRITE_FILE_MODE_WRITE___; def APPEND_MODE ___BUILTIN_WRITE_FILE_MODE_APPEND___; def NULL ___BUILTIN_NULL___; def RSA_SIGN_SHA ___OPENSSL_NID_sha___; def RSA_SIGN_SHA1 ___OPENSSL_NID_sha1___; def RSA_SIGN_RIPE160 ___OPENSSL_NID_ripemd160___; def RSA_SIGN_MD5 ___OPENSSL_NID_md5___; def RSA_SIGN_MD5_SHA1 ___OPENSSL_NID_md5_sha1___; def RSA_SIGN_SHA256 ___OPENSSL_NID_sha256___; def RSA_SIGN_SHA256_WITH_RSA ___OPENSSL_NID_sha256WithRSAEncryption___; def RSA_SIGN_SHA512 ___OPENSSL_NID_sha512___; def RSA_SIGN_SHA512_WITH_RSA ___OPENSSL_NID_sha512WithRSAEncryption___; def RSA_PAD_PKCS1 ___OPENSSL_RSA_PKCS1_PADDING___; def RSA_PAD_OAEP ___OPENSSL_RSA_PKCS1_OAEP_PADDING___; def RSA_PAD_SSLV23 ___OPENSSL_RSA_SSLV23_PADDING___; def RSA_PAD_NO ___OPENSSL_RSA_NO_PADDING___; def RSA_PUBLIC ___OPENSSL_RSA_PUBLIC___; def RSA_PRIVATE ___OPENSSL_RSA_PRIVATE___; def USE_EVP ___OPENSSL_RSA_USE_EVP___; print 'TRUE: ' + TRUE; print 'FALSE: ' + FALSE; print 'WRITE_MODE: ' + WRITE_MODE; print 'APPEND_MODE: ' + APPEND_MODE; print 'NULL: ' + NULL; print 'RSA_SIGN_SHA: ' + RSA_SIGN_SHA; print 'RSA_SIGN_SHA1: ' + RSA_SIGN_SHA1; print 'RSA_SIGN_RIPE160: ' + RSA_SIGN_RIPE160; print 'RSA_SIGN_MD5: ' + RSA_SIGN_MD5; print 'RSA_SIGN_MD5_SHA1: ' + RSA_SIGN_MD5_SHA1; print 'RSA_SIGN_SHA256: ' + RSA_SIGN_SHA256; print 'RSA_SIGN_SHA256_WITH_RSA: ' + RSA_SIGN_SHA256_WITH_RSA; print 'RSA_SIGN_SHA512: ' + RSA_SIGN_SHA512; print 'RSA_SIGN_SHA512_WITH_RSA: ' + RSA_SIGN_SHA512_WITH_RSA; print 'RSA_PAD_PKCS1: ' + RSA_PAD_PKCS1; print 'RSA_PAD_OAEP: ' + RSA_PAD_OAEP; print 'RSA_PAD_SSLV23: ' + RSA_PAD_SSLV23; print 'RSA_PAD_NO: ' + RSA_PAD_NO; print 'RSA_PUBLIC: ' + RSA_PUBLIC; print 'RSA_PRIVATE: ' + RSA_PRIVATE; print 'USE_EVP: ' + USE_EVP;
上面脚本在命令行中的执行结果类似如下所示:
[root@localhost zenglServer]# ./zenglServer -r /v0_25_0/test_def.zl TRUE: 1 FALSE: 0 WRITE_MODE: 1 APPEND_MODE: 2 NULL: 0 RSA_SIGN_SHA: 0 RSA_SIGN_SHA1: 1 RSA_SIGN_RIPE160: 2 RSA_SIGN_MD5: 3 RSA_SIGN_MD5_SHA1: 4 RSA_SIGN_SHA256: 5 RSA_SIGN_SHA256_WITH_RSA: 6 RSA_SIGN_SHA512: 7 RSA_SIGN_SHA512_WITH_RSA: 8 RSA_PAD_PKCS1: 0 RSA_PAD_OAEP: 1 RSA_PAD_SSLV23: 2 RSA_PAD_NO: 3 RSA_PUBLIC: 1 RSA_PRIVATE: 0 USE_EVP: 1 [root@localhost zenglServer]#
当前版本的zenglServer在config.zl配置文件中增加了backlog和timezone的配置:
def TRUE 1; def FALSE 0; def KBYTE 1024; ..................................................................... backlog = 10; // 设置TCP连接队列中可以等待的连接数(backlog的值只是建议值,不同的系统会根据这个值设置不同的等待连接数,例如linux 2.4.7中当backlog为1时,实际可以等待的连接数会是4等),当队列中等待连接的数量满了时,新请求的连接就会报连接被拒绝的错误 timezone = 'Asia/Shanghai'; // 设置时区 pidfile = "zenglServer.pid"; // 设置记录主进程的进程ID的文件名(该文件名可以是相对于当前工作目录的路径)
backlog可以设置zenglServer在TCP连接队列中可以等待的连接数,当连接数满了时,新的请求就会报连接被拒绝的错误,因此,当并发量大的时候,除了增加zenglServer的进程数外,还可以适当的增大backlog的值。此外,timezone配置可以设置zenglServer中脚本所使用的默认时区。
当前版本除了可以在配置文件中使用timezone来配置默认时区外,还可以在脚本中使用新增的bltSetTimeZone模块函数来设置脚本所在的时区,该模块函数在源文件中的定义如下(定义在module_builtin.c文件中):
/** * bltSetTimeZone模块函数,设置当前脚本所在进程的时区 * 第一个参数timezone必须是字符串类型,表示需要设置的时区,例如:America/New_York表示设置为纽约时区,Europe/London表示设置为伦敦时区等 * 具体的时区格式,可以参考GNU官网的介绍:https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html * 返回值为1表示设置成功 * * 示例: use builtin; print bltDate('%Y-%m-%d %H:%M:%S'); // 使用配置文件中timezone变量定义的时区来显示当前时间 bltSetTimeZone("America/New_York"); // 切换到纽约时区 print bltDate('%Y-%m-%d %H:%M:%S'); // 以纽约时区来显示当前时间 bltSetTimeZone("Europe/London"); // 切换到伦敦时区 print bltDate('%Y-%m-%d %H:%M:%S'); // 以伦敦时区来显示当前时间 bltSetTimeZone("Asia/Shanghai"); // 切换到亚洲上海时区 print bltDate('%Y-%m-%d %H:%M:%S'); // 以上海时区来显示当前时间 bltSetTimeZone(""); // 切换到系统默认时区 print bltDate('%Y-%m-%d %H:%M:%S'); // 使用默认时区来显示当前时间 执行结果类似如下所示: 2022-01-25 19:41:04 2022-01-25 06:41:04 2022-01-25 11:41:04 2022-01-25 19:41:04 2022-01-25 11:41:04 模块函数版本历史: - v0.25.0版本新增此模块函数 */ ZL_EXP_VOID module_builtin_set_time_zone(ZL_EXP_VOID * VM_ARG, ZL_EXP_INT argcount) { ZENGL_EXPORT_MOD_FUN_ARG arg = {ZL_EXP_FAT_NONE,{0}}; const char * func_name = "bltSetTimeZone"; if(argcount < 1) zenglApi_Exit(VM_ARG,"usage: %s(timezone)", func_name); zenglApi_GetFunArg(VM_ARG,1,&arg); if(arg.type != ZL_EXP_FAT_STR) { zenglApi_Exit(VM_ARG,"the first argument [timezone] of %s must be string", func_name); } char * timezone = (char *)arg.val.str; if(setenv("TZ", timezone, 1) == -1) { zenglApi_Exit("%s: failed to setenv TZ [%d] %s \n", (char *)func_name, errno, strerror(errno)); } tzset(); zenglApi_SetRetVal(VM_ARG, ZL_EXP_FAT_INT, ZL_EXP_NULL, 1, 0); }
该模块函数接受一个字符串参数,表示需要设置的时区,例如:America/New_York表示设置为纽约时区,Europe/London表示设置为伦敦时区等,具体的时区格式,可以参考GNU官网的介绍:https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
为了测试上面的bltSetTimeZone模块函数,当前版本在 my_webroot/v0_25_0/ 目录中增加了test_timezone.zl的测试脚本:
use builtin; print bltDate('%Y-%m-%d %H:%M:%S'); bltSetTimeZone("America/New_York"); print bltDate('%Y-%m-%d %H:%M:%S'); bltSetTimeZone("Europe/London"); print bltDate('%Y-%m-%d %H:%M:%S'); bltSetTimeZone("Asia/Shanghai"); print bltDate('%Y-%m-%d %H:%M:%S'); bltSetTimeZone(""); print bltDate('%Y-%m-%d %H:%M:%S');
上面脚本分别切换到了纽约时区,伦敦时区,以及亚洲上海时区进行测试,该脚本的执行结果类似如下所示:
[root@localhost zenglServer]# ./zenglServer -r /v0_25_0/test_timezone.zl 2022-01-29 13:40:08 2022-01-29 00:40:08 2022-01-29 05:40:08 2022-01-29 13:40:08 2022-01-29 05:40:08 [root@localhost zenglServer]#
梦不会逃走,逃走的一直都是自己。
—— 蜡笔小新