📄 myapp.c
字号:
/* A trivial application to demonstrate the RTA package. *//* We define a structure with a user-editable string and *//* two integers. One of the integers, zalarm, is set by *//* the user. The other integer, zcount, is incremented *//* on each transition of zalarm from one-to-zero or from *//* zero-to-one. We print a message to the console each *//* time a transition occurs. The string, zname, is *//* considered a configuration value and is saved in a *//* disk file whenever it is updated. This code is *//* limited in that only one user can connect at a time. *//* Build with 'gcc myapp.c -lrtadb' */#include <stdio.h>#include <stdlib.h>#include <stddef.h> /* for 'offsetof' */#include <unistd.h> /* for 'read/write/close' */#include <string.h> /* for 'memset' */#include <sys/socket.h>#include <netinet/in.h>#include "../src/rta.h"/* You may need to change the above line to match where *//* you are building this program. *//* We detect transitions of zalarm in a write callback. *//* Here is the forward reference for it. *//* Forward references */int zedgedetect(char *tbl, char *col, char *sql, void *pr, int rowid, void *poldrow);/* We need to allocate buffers for the text of the SQL *//* command from the client and for the response returned *//* to the client. Here we are using 500 and 50000 bytes *//* repectively. */#define INSZ 500#define OUTSZ 5000#define Z_NAME_LEN 20struct ZData { char zname[Z_NAME_LEN]; int zalarm; int zcount;};#define ROW_COUNT 5struct ZData zdata[ROW_COUNT];/* Here is the array of COLDEFs that describe the columns *//* in our table. The information in these structures is *//* derived from the data structure itself and from our *//* problem statement. Note that you can have columns *//* (members) in your data structure that are not *//* described by a COLDEF. Such hidden columns might be *//* useful for information that you do not want visible to *//* the user interfaces. */COLDEF zcols[] = { { "ztable", /* the table name */ "zname", /* the column name */ RTA_STR, /* it is a string */ Z_NAME_LEN, /* number of bytes */ offsetof(struct ZData, zname), /* location in struct */ RTA_DISKSAVE, /* flags: configuration data */ (int (*)()) 0, /* called before read */ (int (*)()) 0, /* called after write */ "User assigned name for this row. The names are " "saved to a disk file since they are part of the " "configuration. Note that the maximum name length " "is 20 characters including the terminating NULL. " }, { "ztable", /* the table name */ "zalarm", /* the column name */ RTA_INT, /* it is an integer */ sizeof(int), /* number of bytes */ offsetof(struct ZData, zalarm), /* location in struct */ 0, /* no flags */ (int (*)()) 0, /* called before read */ zedgedetect, /* called after write */ "A user read/write value. Print a message on all transitions " "from high-to-low or from low-to-high. Do not display anything " "if a write does not cause a transition. A write callback " "translates all non-zero values to a value of one." }, { "ztable", /* the table name */ "zcount", /* the column name */ RTA_INT, /* it is an integer */ sizeof(int), /* number of bytes */ offsetof(struct ZData, zcount), /* location in struct */ RTA_READONLY, /* flags: a statistic */ (int (*)()) 0, /* called before read */ (int (*)()) 0, /* called after write */ "The number of transitions of zalarm. This is " "a read-only statistic." },};TBLDEF ztbl = { "ztable", /* table name */ zdata, /* address of table */ sizeof(struct ZData), /* length of each row */ ROW_COUNT, /* number of rows */ (void *) NULL, /* linear array; no need for an iterator */ (void *) NULL, /* no iterator callback data either */ zcols, /* array of column defs */ sizeof(zcols) / sizeof(COLDEF), /* the number of columns */ "/tmp/zsave.sql", /* Save config in /tmp directory */ "A sample table showing column flags and write callbacks"};/* In the TBLDEF we give the name of the table, its start *//* address, the size of each row, the number of rows, a *//* pointer to the table of COLDEFS for this table, and *//* the number of columns in the table. Here we are *//* specifying a save file. This file will be used save *//* all of the RTA_DISKSAVE columns, which, in our case, *//* is just the name column. */int main(){ int i; /* a loop counter */ int srvfd; /* File Descriptor for our server socket */ int connfd; /* File Descriptor for conn to client */ struct sockaddr_in srvskt; /* server listen socket */ struct sockaddr_in cliskt; /* socket to the UI/DB client */ socklen_t adrlen; char inbuf[INSZ]; /* Buffer for incoming SQL commands */ char outbuf[OUTSZ]; /* response back to the client */ int incnt; /* SQL command input count */ int outcnt; /* SQL command output count */ int dbret; /* return value from SQL command */ /* init zdata */ for (i=0; i<ROW_COUNT; i++) { zdata[i].zname[0] = (char) 0; zdata[i].zalarm = 0; zdata[i].zcount = 0; } /* tell RTA it about zdata */ if (rta_add_table(&ztbl) != RTA_SUCCESS) { fprintf(stderr, "Table definition error!\n"); exit(1); } /* By-the-way: the following code is pretty horrendous. * It uses blocking IO, ignores error conditions, and * makes wildly optimistic assumptions about socket IO. * My goal is to make the code understandable by getting * it into as few lines as possible. DO NOT USE FOR * PRODUCTION CODE!!! */ /* We now need to open a socket to listen for incoming * client connections. */ adrlen = sizeof (struct sockaddr_in); (void) memset ((void *) &srvskt, 0, (size_t) adrlen); srvskt.sin_family = AF_INET; srvskt.sin_addr.s_addr = INADDR_ANY; srvskt.sin_port = htons (8888); srvfd = socket(AF_INET, SOCK_STREAM, 0); /* no error checks! */ bind(srvfd, (struct sockaddr *) &srvskt, adrlen); listen (srvfd, 1); /* Loop forever accepting client connections */ while (1) { connfd = accept(srvfd, (struct sockaddr *) &cliskt, &adrlen); if (connfd < 0) { fprintf(stderr, "Error on socket/bind/listen/accept\n"); exit(1); } incnt = 0; while (connfd >= 0) { incnt = read(connfd, &inbuf[incnt], INSZ-incnt); if (incnt <= 0) { close(connfd); connfd = -1; } outcnt = OUTSZ;/* The read above uses blocking IO. In a real *//* application we would want to accept the connection and *//* use a select() or poll() to do the multiplexing for us.*//* We are trying keep the like count low in this sample. *//* The real work of RTA occurs with the following call. *//* We pass the string read from the client into the RTA *//* library which parses it, verifies it, executes it, and *//* fills outbuf with the result. We switch on the result *//* of the dbcommand() call to see if we should send the *//* result back to the client or close the connections. *//* Under normal circumstances, the PostgreSQL client will *//* do an orderly close and dbcommand() returns RTA_CLOSE. */ dbret = dbcommand(inbuf, &incnt, outbuf, &outcnt); switch (dbret) { case RTA_SUCCESS: write(connfd, outbuf, (OUTSZ - outcnt)); incnt = 0; break; case RTA_NOCMD: break; case RTA_CLOSE: close(connfd); connfd = -1; break; default: break; } } }}/* zedgedetect(), a write callback to print a message when * the alarm structure member is set from zero-to-one or * from one-to-zero. We also normalize zalarm to 0 or 1. */int zedgedetect(char *tbl, char *col, char *sql, void *pr, int rowid, void *poldrow){ /* we detect an edge by seeing if the old value of * zalarm is different from the new value. */ int oldalarm; int newalarm; /* normalize non-zero values to 1 */ if (((struct ZData *) pr)->zalarm != 0) { ((struct ZData *) pr)->zalarm = 1; } oldalarm = ((struct ZData *) poldrow)->zalarm; newalarm = ((struct ZData *) pr)->zalarm; if (oldalarm != newalarm) { zdata[rowid].zcount++; /* increment counter */ printf("Transition from %d to %d in row %d\n", oldalarm, newalarm, rowid); }/* We always return success in this example. As a *//* reminder, if we return a non-zero value, the row *//* affected is restored to its old value and the client *//* programs gets an error result from the SQL command *//* that it sent. */ return(0); /* always succeeds */}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -