Oracle Tuxedo工作站客户端与服务端的样例程序
服务端代码:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <ctype.h> 5 #include <atmi.h> 6 #include <userlog.h> 7 8 static void trim(char *strIn, char *strOut){ 9 10 char *start, *end, *temp; 11 12 temp = strIn; 13 while (*temp == ' ') 14 { 15 ++temp; 16 } 17 18 start = temp; 19 20 temp = strIn + strlen(strIn) - 1; 21 22 while (*temp == ' '){ 23 --temp; 24 } 25 26 end = temp; 27 28 for (strIn = start; strIn <= end;){ 29 *strOut++ = *strIn++; 30 } 31 32 *strOut = '\0'; 33 34 } 35 36 // return 1 is true , 0 is false 37 static int isDigit(const char* str, int len) 38 { 39 int i; 40 if (len == 0) 41 { 42 return 0; 43 } 44 for (i = 0; i < len; ++i) 45 { 46 if (i == 0 && str[i] == '-') continue; 47 48 if (!isdigit(str[i])) 49 { 50 return 0; 51 } 52 } 53 return 1; 54 } 55 56 static int extractErrorCodeTagValue(const char* source) 57 { 58 char tagBeginStr[256] = { 0 }; 59 char tagEndStr[256] = { 0 }; 60 char errorCodeStr[256] = { 0 }; 61 char errorCodeStrOut[256] = { 0 }; 62 const char *beginPos = NULL; 63 const char *endPos = NULL; 64 const char* ERROR_CODE_TAG = "ERRORCODE"; 65 66 char *workPtr = NULL; 67 int i = 0; 68 69 if (source == NULL || strlen(source) == 0) 70 { 71 return -999; 72 } 73 74 sprintf(tagBeginStr, "<%s>", ERROR_CODE_TAG); 75 sprintf(tagEndStr, "</%s>", ERROR_CODE_TAG); 76 77 beginPos = strstr(source, tagBeginStr); 78 endPos = strstr(source, tagEndStr); 79 80 if (beginPos == NULL || endPos == NULL) 81 { 82 return -999; 83 } 84 85 for (workPtr = (char*)beginPos + strlen(tagBeginStr); workPtr != endPos; workPtr++,i++) 86 { 87 errorCodeStr[i] = *workPtr; 88 } 89 90 if (strlen(errorCodeStr) == 0) 91 { 92 return -999; 93 } 94 95 trim(errorCodeStr, errorCodeStrOut); 96 97 if (!isDigit(errorCodeStrOut, strlen(errorCodeStrOut))) 98 { 99 return -999; 100 } 101 102 return atoi(errorCodeStrOut); 103 104 } 105 106 107 108 EXEC SQL INCLUDE sqlca; 109 110 EXEC SQL BEGIN DECLARE SECTION; 111 char result_out[3096] = ""; 112 char* requestData = NULL; 113 long requestDataLen = 0; 114 char* resultData = NULL; 115 int retErrorCode = 0; 116 EXEC SQL VAR result_out IS STRING(3096); 117 EXEC SQL END DECLARE SECTION; 118 119 TEST(TPSVCINFO *rqst) 120 121 { 122 123 requestData = rqst->data; 124 requestDataLen = rqst->len; 125 126 127 userlog("Request Data is:%s", requestData); 128 129 userlog("Request Data Length is:%d", requestDataLen); 130 131 EXEC SQL EXECUTE 132 DECLARE 133 result_out_sql varchar2(3096); 134 BEGIN 135 result_out_sql := ''; 136 prc_K_testJsdQuery(:requestData,result_out_sql); 137 :result_out := result_out_sql; 138 END; 139 END-EXEC; 140 141 142 userlog("result_out is: %s",result_out); 143 144 retErrorCode = extractErrorCodeTagValue(result_out); 145 userlog("ret Error Code is: %d",retErrorCode); 146 if(retErrorCode != 0) 147 { 148 EXEC SQL ROLLBACK; 149 userlog("executed rollback"); 150 } 151 else 152 { 153 EXEC SQL COMMIT; 154 userlog("executed commit"); 155 } 156 157 resultData = (char *)tpalloc("STRING",NULL,3096 + 1); 158 if(resultData) 159 { 160 memset(resultData,0,3096 + 1); 161 strncpy(resultData,result_out,3096); 162 userlog("result Data is: %s",resultData); 163 userlog("result Data Length is: %d",strlen(resultData)); 164 tpreturn(TPSUCCESS,0,resultData,strlen(resultData),0); 165 tpfree(resultData); 166 } 167 else 168 { 169 tpreturn(TPFAIL,0,NULL,0,0); 170 } 171 172 }
以上代码内嵌了SQL,采用了Oracle的Pro*C/C++ 编程方式,需要运行以下命令生成相应的可以编译的server_test.c文件:
proc USERID=[数据库账户名]/[数据库密码]@si2000 sqlcheck=SEMANTICS ireclen=512 iname=server_test.pc
然后再编译生成好的server_test.c文件:
buildserver -o server_test -f server_test.c -r Oracle_XA -s TEST
以上命令有个-s的参数是服务端代码里面Service Routine的名字,其实就是提供服务的函数名了。
因为Tuxedo是交易中间件,银行里面大量使用了这个。所以服务端的代码不可能不涉及分布式事务,所以需要运行以下命令行生成对应数据库的事务管理服务器(TMS):
buildtms -o TMS_ORA10G -r Oracle_XA
-o参数就是生成的TMS的exe文件名,这个文件的名称需要在TUXCONFIG文件中配置引用,这样启动的tuxedo服务才能使用事务。
然后配置TUXCONFIG文件,配置完成用tmloadcf命令生成加密后的二进制配置文件。
生成完成二进制配置文件之后暂时还不能启动Tuxedo服务,因为服务可能会使用事务。所以需要进入tmadmin命令中配置事务日志:
tmadmin
crdl -b [block_num] -z D:\oracle\product\10.2.0\db_2\tuxedo12.1.3.0.0_VS2010\samples\atmi\connect-database-test\TLOG
crlog -m [master_node_name]
block_num一定要比TUXCONFIG文件中的TLOGSIZE大20-30%
master_node_name 其实就是TUXCONFIG文件中的MASTER 配置项的值,主节点的逻辑ID
以上命令都成功了以后,就可以使用tmboot命令启动Tuxedo服务了。服务端已经完美运行并连接数据库。下面来写客户端代码:
1 /*功能:调用TUXEDO服务端的服务TEST,取EMPNO=1000所对应的ENAME的值,并显示出来*/ 2 #include <stdio.h> 3 #include "atmi.h" 4 main(argc,argv) 5 { 6 7 long reqlen=1024; 8 char *sendbuf; 9 char *rcvbuf; 10 11 char *wsaddrEnv = tuxgetenv("WSNADDR"); 12 if(wsaddrEnv) 13 { 14 fprintf(stderr,"wsnaddr is:%s\n",wsaddrEnv); 15 } 16 /* 与TUXEDO服务端建立连接 */ 17 if (tpinit((TPINIT *) NULL) == -1) 18 { 19 (void) fprintf(stderr,"Tpinit failedn"); 20 exit(1); 21 } 22 23 /* 分配发送缓冲区*/ 24 25 sendbuf = (char *)tpalloc("STRING",NULL,reqlen); 26 27 if ( sendbuf == (char *)NULL) 28 29 { 30 31 printf("tpalloc failedn"); 32 33 tpterm(); 34 35 } 36 37 /* 分配接受缓冲区*/ 38 rcvbuf = (char *)tpalloc("STRING",NULL,reqlen); 39 40 if ( rcvbuf == (char *)NULL) 41 42 { 43 44 printf("tpalloc failedn"); 45 46 tpterm(); 47 48 } 49 50 strcpy(sendbuf,"<AKC190>L2017262210000651420</AKC190><YYBM>0080</YYBM>"); 51 52 /*调用TUXEDO的服务TEST*/ 53 54 if (tpcall("TEST", (char *)sendbuf, 0L, (char **)&rcvbuf, (long *)&reqlen, 0< 0 ) ) 55 /*tpcall("TOUPPER", (char *)sendbuf, 0, (char **)&rcvbuf, &rcvlen, (long)0))*/ 56 { 57 58 printf("tpcall failed,tperrno=%ld,tperrtext=%s\n",tperrno,tpstrerror(tperrno)); 59 60 tpfree(rcvbuf); 61 62 tpterm(); 63 64 exit(1); 65 66 } 67 68 printf("name=%s\n",rcvbuf); 69 70 tpfree(rcvbuf); 71 72 tpfree(sendbuf); 73 74 tpterm(); 75 76 return(0); 77 78 }
然后以上代码用以下命令行来编译:
buildclient -o client_test -f client_test.c -w
-w参数必须加上,因为是远程客户端连接Tuxedo服务(客户端和服务端不在一台物理机上),如果是本地客户端连接Tuxedo服务(客户端和服务端在一台物理机上),就不用加-w
references:
http://blog.163.com/lover_j_j/blog/static/1682474472007101591059797/
https://docs.oracle.com/cd/B14117_01/appdev.101/a97269/pc_01int.htm#sthref50
https://docs.oracle.com/en/database/oracle/oracle-database/12.2/adfns/xa.html#GUID-22284B0A-C63F-471A-96ED-AEA195068944
https://wenku.baidu.com/view/ef4b38c5580216fc710afdcf.html
http://blog.csdn.net/cemer815/article/details/5493081
http://stevenos.iteye.com/blog/362630