C結構體工具DirectStruct(綜合示例一)
1.編寫定義文件,用工具dsc處理之,自動生成XML轉換代碼和ESQL代碼片斷
2.編寫客戶端代碼
3.編寫服務端代碼
4.編譯運行
------------------------------------------------------------
DirectStruct是一個強有力的代碼自動生成工具,它能夠自動生成C結構體與XML、JSON、二進制(帶壓縮)等報文之間的轉換代碼,還能自動生成ESQL代碼片斷,在應用中直接使用自動化代碼以提升開發效率,避免開發冗餘和手工編碼風險。
綜合示例一演示了客戶端把一個C結構體變量打包成XML報文,經過TCP發送給服務端,服務端解包XML報文成C結構體變量,而後經過ESQL方式登記到數據庫表中。經過示例,你能夠看到中間的絕大多數使人頭痛的代碼均可以經過DirectStruct自動生成,這使得實際要編寫的應用代碼變得簡潔和高效。
本示例由於涉及到XML,DirectStruct的XML處理依賴於開源庫fasterxml。
完整示例代碼放在test_demo目錄裏,你也能夠本身運行觀察。
1.編寫定義文件,用工具dsc處理之,自動生成XML轉換代碼和ESQL代碼片斷 git
$ cat IDL_userinfo.dsc STRUCT userinfo { INT 4 user_id STRING 16 user_name STRING 128 email CREATE_SQL "CREATE UNIQUE INDEX userinfo_idx1 ON userinfo ( user_id ) ;" DROP_SQL "DROP INDEX testable_idx1 ;" } $ dsc -f IDL_userinfo.dsc -c-xml -sql -ec-pqsql -c-LOG STRUCT userinfo INT 4 user_id STRING 16 user_name STRING 128 email ok! $ ls -1 IDL_userinfo.* IDL_userinfo.dsc IDL_userinfo.dsc.ESQL.ec IDL_userinfo.dsc.ESQL.eh IDL_userinfo.dsc.LOG.c IDL_userinfo.dsc.c IDL_userinfo.dsc.create.sql IDL_userinfo.dsc.drop.sql IDL_userinfo.dsc.h
$ cat test_client.c ... int test_client() { userinfo u ; char xml_buffer[ 1024 + 1 ] ; int xml_len ; int connect_sock ; struct sockaddr_in connect_addr ; char commheader_buffer[ 4 + 1 ] ; int commheader_len ; int nret ; memset( & u , 0x00 , sizeof(userinfo) ); u.user_id = 101 ; strcpy( u.user_name , "calvin" ); strcpy( u.email , "calvinwilliams.c@gmail.com" ); DSCLOG_userinfo( & u ); memset( xml_buffer , 0x00 , sizeof(xml_buffer) ); xml_len = sizeof(xml_buffer) ; nret = DSCSERIALIZE_XML_userinfo( & u , "GBK" , xml_buffer , & xml_len ) ; if( nret ) { printf( "DSCSERIALIZE_XML_userinfo failed[%d] , errno[%d]\n" , nret , errno ); return -1; } printf( "send[%d][%.*s]\n" , xml_len , xml_len , xml_buffer ); connect_sock = socket( AF_INET , SOCK_STREAM , IPPROTO_TCP ) ; if( connect_sock == -1 ) { printf( "socket failed[%d] , errno[%d]\n" , connect_sock , errno ); return -1; } memset( & connect_addr , 0x00 , sizeof(struct sockaddr_in) ); connect_addr.sin_family = AF_INET; connect_addr.sin_addr.s_addr = inet_addr( "127.0.0.1" ); connect_addr.sin_port = htons( (unsigned short)7878 ); nret = connect( connect_sock , (struct sockaddr *) & connect_addr, sizeof(struct sockaddr) ); if( nret == -1 ) { printf( "connect failed[%d] , errno[%d]\n" , nret , errno ); return -1; } sprintf( commheader_buffer , "%04d" , xml_len ); commheader_len = 4 ; nret = sendn( connect_sock , commheader_buffer , commheader_len ) ; if( nret < 0 ) { printf( "sendn failed[%d] , errno[%d]\n" , nret , errno ); return -1; } nret = sendn( connect_sock , xml_buffer , xml_len ) ; if( nret < 0 ) { printf( "sendn failed[%d] , errno[%d]\n" , nret , errno ); return -1; } close( connect_sock ); return 0; } ...
$ cat test_server.ec ... int test_server() { int listen_sock ; struct sockaddr_in listen_addr ; int on ; int accept_sock ; struct sockaddr_in accept_addr ; socklen_t addrlen ; char commheader_buffer[ 4 + 1 ] ; int commheader_len ; char xml_buffer[ 1024 + 1 ] ; int xml_len ; userinfo u ; int nret ; listen_sock = socket( AF_INET , SOCK_STREAM , IPPROTO_TCP ) ; if( listen_sock == -1 ) { printf( "socket failed[%d] , errno[%d]\n" , listen_sock , errno ); return -1; } on = 1 ; setsockopt( listen_sock , SOL_SOCKET , SO_REUSEADDR , (void *) & on , sizeof(on) ); memset( & listen_addr , 0x00 , sizeof(struct sockaddr_in) ); listen_addr.sin_family = AF_INET; listen_addr.sin_addr.s_addr = inet_addr( "127.0.0.1" ); listen_addr.sin_port = htons( (unsigned short)7878 ); nret = bind( listen_sock , (struct sockaddr *) & listen_addr, sizeof(struct sockaddr) ) ; if( nret == -1 ) { printf( "bind failed[%d] , errno[%d]\n" , nret , errno ); return -1; } nret = listen( listen_sock , 1024 ) ; if( nret == -1 ) { printf( "listen failed[%d] , errno[%d]\n" , nret , errno ); return -1; } addrlen = sizeof(struct sockaddr) ; accept_sock = accept( listen_sock , (struct sockaddr *) & accept_addr, & addrlen ); if( accept_sock == -1 ) { printf( "accept failed[%d] , errno[%d]\n" , accept_sock , errno ); return -1; } memset( commheader_buffer , 0x00 , sizeof(commheader_buffer) ); commheader_len = 4 ; nret = recvn( accept_sock , commheader_buffer , & commheader_len ) ; if( nret == -1 ) { printf( "recvn failed[%d] , errno[%d]\n" , nret , errno ); return -1; } xml_len = atoi(commheader_buffer) ; memset( xml_buffer , 0x00 , sizeof(xml_buffer) ); nret = recvn( accept_sock , xml_buffer , & xml_len ) ; if( nret == -1 ) { printf( "recvn failed[%d] , errno[%d]\n" , nret , errno ); return -1; } close( accept_sock ); close( listen_sock ); printf( "recv[%d][%.*s]\n" , xml_len , xml_len , xml_buffer ); memset( & u , 0x00 , sizeof(userinfo) ); nret = DSCDESERIALIZE_XML_userinfo( "GBK" , xml_buffer , & xml_len , & u ) ; if( nret ) { printf( "DSCDESERIALIZE_XML_userinfo failed[%d] , errno[%d]\n" , nret , errno ); return -1; } DSCLOG_userinfo( & u ); EXEC SQL CONNECT TO 'calvin@127.0.0.1:18432' USER 'calvin' IDENTIFIED BY 'calvin' ; if( SQLCODE ) { printf( "CONNECT failed[%ld][%s]\n" , SQLCODE , SQLSTATE ); return 1; } else { printf( "CONNECT ok\n" ); } EXEC SQL BEGIN WORK ; if( SQLCODE ) { printf( "BEGIN WORK failed[%ld][%s]\n" , SQLCODE , SQLSTATE ); return 1; } else { printf( "BEGIN WORK ok\n" ); } DSCINITV_userinfo(); DSCSTOV_userinfo( & u ); EXEC SQL INSERT INTO userinfo VALUES ( DBVLIST_userinfo ) ; if( SQLCODE ) { printf( "INSERT failed[%ld][%s]\n" , SQLCODE , SQLSTATE ); } else { printf( "INSERT ok\n" ); } if( SQLCODE ) { EXEC SQL ROLLBACK WORK ; if( SQLCODE ) { printf( "ROLLBACK WORK failed[%ld][%s]\n" , SQLCODE , SQLSTATE ); } else { printf( "ROLLBACK WORK ok\n" ); } } else { EXEC SQL COMMIT WORK ; if( SQLCODE ) { printf( "COMMIT WORK failed[%ld][%s]\n" , SQLCODE , SQLSTATE ); } else { printf( "COMMIT WORK ok\n" ); } } EXEC SQL DISCONNECT ; if( SQLCODE ) { printf( "DISCONNECT failed[%ld][%s]\n" , SQLCODE , SQLSTATE ); return 1; } else { printf( "DISCONNECT ok\n" ); } return 0; } ...
$ # 執行建表SQL腳本IDL_userinfo.dsc.create.sql $ ... $ make gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I. -I/root/local/postgresql/include -I/home/calvin/exinc/fasterxml -c IDL_userinfo.dsc.c gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I. -I/root/local/postgresql/include -I/home/calvin/exinc/fasterxml -c test_client.c gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -o test_client IDL_userinfo.dsc.o test_client.o -L. -L/root/local/postgresql/lib -lecpg -L/home/calvin/exlib -lfasterxml gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I. -I/root/local/postgresql/include -I/home/calvin/exinc/fasterxml -E -x c test_server.ec > test_server.ecE ecpg -h test_server.ecE -o test_server.c sed -i 's/NULL/0/g' test_server.c gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -I. -I/root/local/postgresql/include -I/home/calvin/exinc/fasterxml -c test_server.c gcc -g -fPIC -O2 -Wall -Werror -fno-strict-aliasing -o test_server IDL_userinfo.dsc.o IDL_userinfo.dsc.ESQL.o test_server.o -L. -L/root/local/postgresql/lib -lecpg -L/home/calvin/exlib -lfasterxml
$ ./test_client userinfo.user_id[101] userinfo.user_name[calvin] userinfo.email[calvinwilliams.c@gmail.com] send[158][<?xml version="1.0" encoding="GBK"?> <userinfo> <user_id>101</user_id> <user_name>calvin</user_name> <email>calvinwilliams.c@gmail.com</email> </userinfo> ]
$ ./test_server recv[158][<?xml version="1.0" encoding="GBK"?> <userinfo> <user_id>101</user_id> <user_name>calvin</user_name> <email>calvinwilliams.c@gmail.com</email> </userinfo> ] userinfo.user_id[101] userinfo.user_name[calvin] userinfo.email[calvinwilliams.c@gmail.com] CONNECT ok BEGIN WORK ok INSERT ok COMMIT WORK ok DISCONNECT ok $ psql -h 127.0.0.1 -p 18432 -U calvin Password for user calvin: psql (9.0.3) Type "help" for help. calvin=# select * from userinfo; user_id | user_name | email ---------+-----------+---------------------------- 101 | calvin | calvinwilliams.c@gmail.com (1 row)是否是很方便?歡迎使用DirectStruct,若是你使用中碰到了問題或者有更酷的想法請告訴我,謝謝 ^_^ 首頁傳送門 : [url]http://git.oschina.net/calvinwilliams/DirectStruct[/url] 做者郵箱 : calvinwilliams.c@gmail.com