What time is it? The DayTime Server

Một phần của tài liệu Manning android in action 3rd (Trang 399 - 407)

Although we don’t talk about it much today, Linux systems (and more generically, Unix systems) have a service running that provides the server’s current date and time.

This application, known as a DayTime Server, typically runs as a daemon (which means it runs in the background and isn’t connected to a particular shell). For our purposes, we’ll implement a basic DayTime Server for Android/Linux, but we won’t worry about turning it into a background service.

This application helps exercise our interest in developing Android/Linux applica- tions. First and most important, it’s an application of some significance beyond a sim- ple printf statement. Second, once this application is built, you’ll write an Android/

Java application to interact with the DayTime Server.

13.3.1 DayTime Server application

Our DayTime Server application has a basic function: the application listens on a TCP port for incoming socket connections. When a connection is made, the application writes a short textual string representation of the date and time via the socket, closes the socket, and returns to listening for a new connection.

In addition to the TCP socket interactions, our application logs requests to a SQLite database. Why? Because we can! The purpose of this application is to demonstrate nontrivial activities in the Android/Linux environment, including the use of the SQLite system library. Let’s get started by examining the DayTime Server application.

13.3.2 daytime.c

The DayTime Server application can be broken into two basic functional parts. The first is the TCP socket server.

Our DayTime Server application binds to TCP port 1024 when looking for new connections. Ordinarily, a daytime service binds to TCP port 13, but Linux has a secu- rity feature where only trusted users can bind to any port below 1023. The second fea- ture is the insertion of data into a SQLite database. The following listing shows the code for the DayTime Server application.

#include <time.h>

#include <stdio.h>

#include <string.h>

#include <errno.h>

#include <arpa/inet.h>

#include <netinet/in.h>

#include <sys/socket.h>

#include <resolv.h>

#include "sqlite3.h"

int PORTNUMBER = 1024;

#define htons(a)

( ((a & 0x00ff) << 8) | ((a & 0xff00) >> 8)) void RecordHit(char * when)

{

int rc;

sqlite3

*db;

char *zErrMsg = 0;

char sql[200];

rc = sqlite3_open("daytime_db.db",&db);

if( rc ) {

printf( "Can't open database: %s\n", sqlite3_errmsg(db));

sqlite3_close(db);

return;

}

bzero(sql,sizeof(sql));

sprintf(sql,"insert into hits values (DATETIME('NOW'),'%s');",when);

rc = sqlite3_exec(db, sql, NULL, 0, &zErrMsg);

if( rc!=SQLITE_OK ) {

printf( "SQL error: %s\n", zErrMsg);

}

sqlite3_close(db);

}

Listing 13.8 daytime.c

B Import required headers

Listening port number

C

Define helpful macro

D

Interact E

with SQLite

int main(int argc, char **argv) {

int listenfd, connfd;

struct sockaddr_in servaddr;

char buf[100];

time_t ticks;

int done = 0;

int rc;

fd_set readset;

int result;

struct timeval tv;

printf("Daytime Server\n");

listenfd = socket(AF_INET,SOCK_STREAM,0);

bzero(&servaddr,sizeof(servaddr));

servaddr.sin_family = AF_INET;

servaddr.sin_addr.s_addr = INADDR_ANY;

servaddr.sin_port = htons(PORTNUMBER);

rc = bind(listenfd, (struct sockaddr *) &servaddr,sizeof(servaddr));

if (rc != 0) {

printf("after bind,rc = [%d]\n",rc);

return rc;

}

listen(listenfd,5);

while (!done) {

printf("Waiting for connection\n");

while (1) {

bzero(&tv,sizeof(tv));

tv.tv_sec = 2;

FD_ZERO(&readset);

FD_SET(listenfd, &readset);

result = select(listenfd + 1, &readset, &readset, NULL, &tv);

if (result >= 1) {

printf("Incoming connection!\n");

break;

}

else if (result == 0) {

printf("Timeout.\n");

continue;

} else {

printf("Error, leave.\n");

return result;

} }

printf("Calling accept:\n");

connfd = accept(listenfd, (struct sockaddr *) NULL, NULL);

printf("Connecting\n");

ticks = time(NULL);

Set up and listen on socket F

Accept socket connection

G

sprintf(buf,"%.24s",ctime(&ticks));

printf("sending [%s]\n",buf);

write(connfd,buf,strlen(buf));

close(connfd);

RecordHit(buf);

}

return 0;

}

As with many C language applications, a number of headers B are required, includ- ing definitions and prototypes for time functions, SQLite functions, and TCP sockets.

Note that the sqlite3.h header file isn’t provided in the CodeSourcery tool chain. This file was acquired from a sqlite3 distribution, and the file was copied into the local directory along with daytime.c. This is why the include file is delimited with quotation marks rather than <>, which is used for finding include files in the system or compiler path. The htons function is typically implemented in the library named socket (lib- socket.so). Android doesn’t provide this library, nor was this found in any of the sys- tem libraries. Therefore htons is defined here as a macro D. This macro is required to get the network byte ordering correct. When the application is running, we can ver- ify this port by running netstat –tcp on the command line in the adb shell.

The standard TCP port for a DayTime Server is port 13. In C, the application is using port 1024 because our application can’t bind to any port numbered 1023 or below. Only system processes may bind to ports below 1024.

In the RecordHit() function, you see SQLite interaction E. The RecordHit() function is responsible for inserting a record into the SQLite database created for this application.

Jumping into the main function, you see the socket functions in use to listen on a socket for incoming connections F. When a connection is accepted G, the current system time is sent to the calling client. After this, the application makes a record of the transaction by calling the RecordHit() function H.

That’s all the code necessary to implement our Android/Linux DayTime Server application. Let’s look next at the SQLite 3 database interaction in more detail.

13.3.3 The SQLite database

This application employs a simple database structure created with the SQLite 3 appli- cation. We interact with SQLite 3 from the adb shell environment, as shown in fig- ure 13.7.

The purpose of this database is to record data each time the DayTime Server pro- cesses an incoming request. From a data perspective, this sample is boring, as it simply records the system time along with the text returned to the client (this text is a ctime- formatted time string). Though somewhat redundant from a data perspective, the purpose is to demonstrate the use of SQLite from our C application, utilizing the Android/Linux resident sqlite3 library, libsqlite.so.

Record activity

H

The previous section of code outlined the syntax for inserting a row into the database;

this section shows how to interact with the database using the SQLite 3 tool. The sequence shown in figure 13.7 is broken out and explained in the following listing.

# pwd pwd /data/ch13

# sqlite3 daytime_db.db sqlite3 daytime_db.db SQLite version 3.5.0

Enter ".help" for instructions sqlite> .databases

.databases

seq name file

--- --- --- 0 main /data/ch13/daytime_db.db

sqlite> .tables .tables

hits

sqlite> .schema hits .schema hits

CREATE TABLE hits (hittime date,hittext text);

sqlite> .header on .header on

Listing 13.9 Interacting with a SQLite database

Figure 13.7 Interact with SQLite 3 from the command line in the adb shell.

Connect to database file

B

C

Examine database structure

Create statement

D

sqlite> .mode column .mode column

sqlite> select * from hits;

select * from hits;

hittime hittext

--- --- 2008-07-29 07:31:35 Tue Jul 29 07:31:35 2008 2008-07-29 07:56:27 Tue Jul 29 07:56:27 2008 2008-07-29 07:56:28 Tue Jul 29 07:56:28 2008 2008-07-29 07:56:29 Tue Jul 29 07:56:28 2008 2008-07-29 07:56:30 Tue Jul 29 07:56:30 2008 sqlite> .exit

.exit

#

The SQLite database operates in a similar fashion to other, modern SQL-based envi- ronments. In listing 13.9, you see the output from an interactive session where the database for this chapter’s sample application is opened B. A series of commands given at the sqlite> prompt C display the contents of the database in terms of struc- ture. The schema command dumps the DDL (Data Definition Language) for a particu- lar table. In this case, you see the CREATE TABLE instructions for the hits table D. Viewing the data is simple with the use of the familiar select statement E.

To run the sample code yourself, you’ll want to execute the following command sequence from an adb shell:

cd /data/ch13

sqlite3 daytime_db.db

create table hits (hittime date,hittext text);

.exit

The SQLite database engine is known for its simplicity. This section displayed a simple interaction and just how easy it is to employ. In addition, the SQLite 3 database may be pulled from the Android Emulator and used on the development machine, as shown in figure 13.8.

Select rows

E

Figure 13.8 The SQLite database on the development machine

This feature makes Android a compelling platform for mobile data collection applications because syncing data can be as simple as copying a database file that’s compatible across multiple platforms.

13.3.4 Building and running the DayTime Server

To build this application, we need to combine the components of the previous few sections. We know that the application requires a startup component and must also link against multiple libraries. Because the application interacts with the SQLite data- base, we must link against the sqlite library in addition to the c and android_runtime libraries. The full build script is shown in the next listing.

arm-none-linux-gnueabi-gcc -c daytime.c arm-none-linux-gnueabi-gcc -c -o crt0.o crt.S

arm-none-linux-gnueabi-ld --entry=_start --dynamic-linker /system/bin/linker -nostdlib -rpath /system/lib -rpath-link \android\system\lib -L

\android\system\lib -l c -l android_runtime -l sqlite -o daytime daytime.o crt0.o

C:\software\google\<path to android sdk>\tools\adb

push daytime /data/ch13 g:\tools\adb shell "chmod 777 /data/ch13/daytime"

The build script begins by compiling the main source file, daytime.c. The next line compiles the crt.S file, which we introduced in listing 13.7 for our C runtime initializa- tion. The linker command contains a number of switches to create the desired appli- cation. Note the parameter to the linker to include the sqlite library. Note also the inclusion of both daytime.o and crt0.o object files as inputs to the linker. Both are required to properly construct the DayTime Server application. The input files are found in local (to the development machine) copies of the libraries. And adb is employed to push the executable file to the Android Emulator and to modify the per- missions, saving a manual step.

Running the DayTime Server application is the easy and fun part of this exercise.

Here’s a rundown of the sequence shown in figure 13.9:

1 Start the shell by running adbshell.

2 Change directories to /data/ch13, where the application resides, previously pushed there with an adb push command.

3 Run the ./daytime application.

4 The application binds to a port and begins listening for an incoming connection.

5 A timeout occurs prior to a connection being made. The application displays the timeout and returns to look for connections again.

6 A connection is detected and subsequently accepted.

Listing 13.10 Daytime application build script

7 The time string is constructed and sent to the client.

8 A record is inserted into the database with the shown sql statement.

9 You kill the application and restart the shell. Note that this is because you didn’t build a clean way of killing the DayTime Server. A proper version of the applica- tion would be to convert it to a daemon, which is beyond the scope of our dis- cussion here.

10 Run sqlite3 to examine the contents of the application’s database.

11 Perform a select against the hits table, where you see the recently inserted record.

You’ve built an Android/Linux application that implements a variant of the traditional DayTime Server application as well as interacts with a SQL database. Not too shabby when you consider that this is a telephone platform! Let’s move on to examine the Android/Java application used to exercise the DayTime Server, our Daytime Client.

Figure 13.9 DayTime Server running in the shell

Một phần của tài liệu Manning android in action 3rd (Trang 399 - 407)

Tải bản đầy đủ (PDF)

(662 trang)