C structure tool DirectStruct (Comprehensive example 1)
1. Write a definition file, process it with the tool dsc, and automatically generate XML conversion code and ESQL code fragments
2. Write client code
3. Write server code
4. Compile and run
--- -------------------------------------------------- -------
DirectStruct is a powerful automatic code generation tool, it can automatically generate the conversion code between C structure and XML, JSON, binary (with compression) and other messages, and can also automatically generate ESQL code Fragments, use automated code directly in the application to improve development efficiency and avoid development redundancy and hand-coding risks.
Comprehensive example 1 demonstrates that the client packs a C structure variable into an XML message, and sends it to the server through TCP. The server unpacks the XML message into a C structure variable, and then registers it in the database table through ESQL. Through the example, you can see that most of the annoying code in the middle can be automatically generated by DirectStruct, which makes the actual application code to be written concise and efficient.
Because this example involves XML, DirectStruct's XML processing relies on the open source library fasterxml.
The complete example code is placed in the test_demo directory, and you can also run the observation yourself.
1. Write a definition file, process it with the tool dsc, and automatically generate XML conversion code and ESQL code snippets
$ 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
XML conversion functions are defined in IDL_userinfo.dsc.c and declared in IDL_userinfo.dsc.h.
ESQL code snippets are defined in IDL_userinfo.dsc.ESQL.ec and declared in IDL_userinfo.dsc.ESQL.eh.
In IDL_userinfo.dsc.LOG.c, there is a function to output all field values of the userinfo structure variable to the standard output.
IDL_userinfo.dsc.create.sql is the SQL script to create the table userinfo, and IDL_userinfo.dsc.drop.sql is the SQL script to destroy the table.
2. Write client code
$ 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 , "[email protected]" );
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;
}
...
First fill in the userinfo variable u of the userinfo structure, and use the automatically generated function DSCLOG_userinfo to print the entire structure to the screen.
Then use the automatically generated function DSCSERIALIZE_XML_userinfo to convert the C structure userinfo variable u to an XML message.
Finally, it is sent to the server through TCP (communication header (4 bytes) + communication body (XML message)).
3. Write server-side code
$ 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 '[email protected]: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;
}
...
First create a TCP server to receive data (communication header (4 bytes) + communication body (XML message)).
Then use the automatically generated function DSCDESERIALIZE_XML_userinfo to unpack the XML into the C structure userinfo variable u, and use the automatically generated function DSCLOG_userinfo to print the entire structure to the screen.
Finally, connect to the database, and directly register the C structure userinfo variable u into the table userinfo with the automatically generated ESQL code fragment.
That is, XML message -> C structure userinfo variable u -> table userinfo, where the data structures are automatically generated from IDL_userinfo.dsc without manual coding.
4. Compile and run
$ # 执行建表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[[email protected]]
send[158][<?xml version="1.0" encoding="GBK"?>
<userinfo>
<user_id>101</user_id>
<user_name>calvin</user_name>
<email>[email protected]</email>
</userinfo>
]
$ ./test_server
recv[158][<?xml version="1.0" encoding="GBK"?>
<userinfo>
<user_id>101</user_id>
<user_name>calvin</user_name>
<email>[email protected]</email>
</userinfo>
]
userinfo.user_id[101]
userinfo.user_name[calvin]
userinfo.email[[email protected]]
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 | [email protected]
(1 row)
Home Portal: [url]http://git.oschina.net/calvinwilliams/DirectStruct[/url]
author Email: [email protected]