C structure tool DirectStruct (synthetic example 1)

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



The userinfo structure is defined in 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;
}
...



Code description:
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;
}
...



Code description:
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



Execute test_server, and execute test_client in another terminal, which are displayed as follows

$ ./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)



Is it convenient? Welcome to use DirectStruct, if you encounter problems or have more cool ideas, please let me know, thank you ^_^

Home Portal: [url]http://git.oschina.net/calvinwilliams/DirectStruct[/url]
author Email: [email protected]

{{o.name}}
{{m.name}}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324146485&siteId=291194637