Saturday, May 23, 2009

Passing Complex Types Between TCP Client and Server

Matrix Transpose with Readn&Writen:

In order to pass an array between a TCP client and server, it is suitable to place your array in a structure.

For this sample which is aimed to pass a 5X10 integer array from client to server and return back the transpose of that 5X10 array back to the client; define one structure for the 5X10 integer array you pass to the server, and another structure for the result 10X5 integer array that you return back to the client.

Place both structure definitions and Readn&Writen functions in a matrix.h file.Writen is used to send the structure to the server by client.Readn is used to read the reply, and then print the result at client side by using printf function as defined by Stevens code.

Server reads the arguments by calling Readn,takes the transpose of the 5X10 array passed to the server-side and by using Writen, 10X5 matrix is returned back to the client.

In addition to client and server source code files an extra header file is used to hold 2 structures and Readn&Writen method implementations.

client-source.c file is as follows:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/in.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include "matrix.h"

int main(int argc,char **argv)
{
    int clientfd;
    short int port_no;
    char msg[1000];
    struct sockaddr_in servaddr;
    char *server_ip_address;
    struct matrices matrix;
    struct matriceresult matriceresult;
    if(argc!=5){
       printf("Usage Format: ./client -a <IPAddress> -p <PortNumber>\n");
       printf("Sample Run: ./client -a 127.0.0.1 -p 2000\n");
       exit(1);
    }
    server_ip_address=(char *)argv[2];
    port_no = atoi(argv[4]);
    printf("Client will connect to the server at IP %s, port #%d\n", server_ip_address, port_no);
   
    // Create client socket.
    if((clientfd = socket(AF_INET, SOCK_STREAM, 0))<0 br="">      printf("Socket could not be created\n");
      printf("errno %i: %s\n",errno,strerror(errno));
      exit(1);
    }
    printf("Client socket created\n");
    errno=0;
    // Connect to the server client
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(port_no);
    if((inet_pton(AF_INET, server_ip_address, &servaddr.sin_addr))<=0){
      printf("inet_pton error for %s\n",server_ip_address);
      printf("errno %d: %s\n",errno,strerror(errno));
      exit(1);
    }
    errno=0;
    if((connect(clientfd, (struct sockaddr *) &servaddr, sizeof(servaddr)))<0 br="">       printf("Connect error\n");
       printf("errno %d: %s\n",errno,strerror(errno));
       exit(1);
    }
    printf("Client socket connected\n");

    //fill initial matrice to be sent from the client to the server. 
    int i,j;
    for(i=0;i<5 br="" i="">      for(j=0;j<10 br="" j="">        matrix.matrice[i][j]=rand()%100;
    //print matrice
    printf("Printing initial 5X10 matrice at client side\n");
    int k,l;
    for(k=0;k<5 br="" k="">      for(l=0;l<10 br="" l="">        printf("%d\t",matrix.matrice[k][l]);
      printf("\n"); 
    }
    writen(clientfd,&matrix,sizeof(matrix));
    readn(clientfd,&matriceresult,sizeof(matriceresult));
    printf("Client received 10X5 matrix from server! Printing Transposed New Matrix at Client\n");
    int m,n;
    for(m=0;m<10 br="" m="">       for(n=0;n<5 br="" n="">         printf("%d\t",matriceresult.resultmatrice[m][n]);
       printf("\n"); 
    }
    close(clientfd);
    return 0;
}

server-source.c file is as follows:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/in.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include "matrix.h"

extern int errno;

int main(int argc,char **argv)
{
    int clientaddrlen, listenfd, connectfd, bytes_rcvd, listen_queue_size=1;
    short int port_no;
    char buffer[1000];
    struct sockaddr_in servaddr, clientaddr;
    pid_t  childpid;
    int status;
    struct matrices matrix;
    struct matriceresult matriceresult;
    
    if(argc!=3){
       printf("Usage Format: ./server -p <PortNumber>\n");
       printf("Sample Run: ./server -p 2000\n");
       exit(1);
    }
    port_no = atoi(argv[argc-1]);
    printf("Server running at port #%d\n", port_no);

    // Create server socket.
    if ( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        fprintf(stderr, "Cannot create server socket! errno %i: %s\n",errno,strerror(errno));
        exit(1);
    }
    printf("Server socket created\n");

    // Bind (attach) this process to the server socket.
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(port_no);
    errno = bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
    if(errno < 0)
    {
        printf("Server bind failure errno %i: %s\n",errno,strerror(errno));
        exit(1);
    }
    printf("Server socket is bound to port #%d\n", port_no);

    // Turn 'listenfd' to a listening socket. Listen queue size is 1.
    errno=listen(listenfd,listen_queue_size);
    if(errno < 0)
    {
        printf("Server listen failure errno %i: %s\n",errno,strerror(errno));
        exit(1);
    }
    printf("Server listening with a queue of size %d. \n", listen_queue_size);

    // Wait for connection(s) from client(s).
    while (1)
    {
        clientaddrlen = sizeof(clientaddr);
        connectfd = accept(listenfd, (struct sockaddr *) &clientaddr, &clientaddrlen);
        Readn(connectfd,&matrix,sizeof(matrix));
    //transpose the matrix that sent from client to server 
    int i,j;        
    for(i=0;i<5 br="" i="">      for(j=0;j<10 br="" j="">        matriceresult.resultmatrice[j][i]=matrix.matrice[i][j];
      }
    }
    //send resultMatrix to client side
    Writen(connectfd,&matriceresult,sizeof(matriceresult));
    }
    return 0;
}

matrix.h file is as follows:
#ifndef __matrix_h
#define __matrix_h
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/in.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

struct matrices{
int matrice[5][10];
};

struct matriceresult{
int resultmatrice[10][5];
};

ssize_t writen(int fd, const void *vptr, size_t n)
{
 size_t  nleft;
 ssize_t  nwritten;
 const char *ptr;

 ptr = vptr;
 nleft = n;
 while (nleft > 0) {
  if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
   if (errno == EINTR)
    nwritten = 0;  /* and call write() again */
   else
    return(-1);   /* error */
  }
  nleft -= nwritten;
  ptr   += nwritten;
 }
 return(n);
}
/* end writen */

void Writen(int fd, void *ptr, size_t nbytes)
{
 if (writen(fd, ptr, nbytes) != nbytes)
  printf("writen error");
}

ssize_t readn(int fd, void *vptr, size_t n)
{
 size_t nleft;
 ssize_t nread;
 char *ptr;

 ptr = vptr;
 nleft = n;
 while (nleft > 0) {
  if ( (nread = read(fd, ptr, nleft)) < 0) {
   if (errno == EINTR)
    nread = 0;  /* and call read() again */
   else
    return(-1);
  } else if (nread == 0)
   break;    /* EOF */

  nleft -= nread;
  ptr   += nread;
 }
 return(n - nleft);  /* return >= 0 */
}
/* end readn */

ssize_t Readn(int fd, void *ptr, size_t nbytes)
{
 ssize_t  n;

 if ( (n = readn(fd, ptr, nbytes)) < 0)
  printf("readn error");
 return(n);
}
#endif /* __matrix_h */


Sample run can be created as follows:

1-)Create server and client executables :

$ cc -o server server.c matrix.h
$ cc -o client client.c matrix.h

2-)Run server at the same tab

$ ./server -p 2000

3-)Open a new tab, run client

$ ./client -a 127.0.0.1 -p 2000

You can get client.c, server.c and matrix.h files from the links.Application tested on ubuntu9.04.

Friday, May 22, 2009

TCP Echo Client Server

When writing a TCP client server program in unix environment, elementary socket functions are used.As described at Stevens book these elementary functions are listed as:

-socket : To perform network I/O, the first thing a process must do is call the socket function.
-connect : used by a TCP client to establish a connection with a TCP server.
-bind : assigns a local protocol address to a socket.
-listen : called by only a TCP server and it converts an unconnected socket into a passive socket.
-accept :called by a TCP server to return the next completed connection from the front of the completed connection queue.
-fork :In Unix environment it is used to create a new process. By using fork() a process makes a copy of itself so that one copy can handle one operation while the other does another task.
-close : close a socket and terminate a TCP connection.

By using above elementary functions we can build our simple echo client and server programs. In this program, when a client connects to the server, the server will use fork() to create a new child process.

Newly created child process will serve the client. The child process terminates after the client sends its message and breaks the connection. The algorithm is as follows:

If this is the child process:
- Close listenfd since it is the responsibility of the parent to handle incoming connections.
- Display the message "Child process serving the client."
- Read the message from the client and display it.
- Close connectfd.
- Exit. The child process was created only to serve the client.

Since the client has transmitted its message and the connection is terminated, the child must terminate.

If this is the parent process:
- Close connectfd since it is the responsibility of the child process to serve the client.
- Go back to accept. Note that the server (parent) runs indefinitely.

client-source.c file is as follows:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/in.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
int main(int argc,char **argv)
{
    int clientfd;
    short int port_no;
    char msg[1000];
    struct sockaddr_in servaddr;
    char *server_ip_address;
    if(argc!=5){
       printf("Usage Format: ./client -a <IPAddress> -p <PortNumber>\n");
       printf("Sample Run: ./client -a 127.0.0.1 -p 2000\n");
       exit(1);
    }
    server_ip_address=(char *)argv[2];
    port_no = atoi(argv[4]);
    printf("Client will connect to the server at IP %s, port #%d\n", server_ip_address, port_no);
   
    // Create client socket.
    if((clientfd = socket(AF_INET, SOCK_STREAM, 0))<0 br="">       printf("Socket could not be created\n");
       printf("errno %i: %s\n",errno,strerror(errno));
       exit(1);
    }
    printf("Client socket created\n");
    errno=0;
    // Connect to the server client
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(port_no);
    if((inet_pton(AF_INET, server_ip_address, &servaddr.sin_addr))<=0){
      printf("inet_pton error for %s\n",server_ip_address);
      printf("errno %d: %s\n",errno,strerror(errno));
      exit(1);
    }
    errno=0;
    if((connect(clientfd, (struct sockaddr *) &servaddr, sizeof(servaddr)))<0 br="">      printf("Connect error\n");
      printf("errno %d: %s\n",errno,strerror(errno));
      exit(1);
    }
    printf("Client socket connected\n");
    // Read one line of message from the input and send it to the server.
    printf("Enter the message to be sent to the server: ");
    scanf("%s", msg);
    send(clientfd, msg, strlen(msg)+1, 0);
    close(clientfd);
    printf("Client sent the message and disconnected. \n");
    return 0;
}


server-source.c file is as follows:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/in.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
extern int errno;
int main(int argc,char **argv)
{
    int clientaddrlen, listenfd, connectfd, bytes_rcvd, listen_queue_size=1;
    short int port_no;
    char buffer[1000];
    struct sockaddr_in servaddr, clientaddr;
    pid_t  childpid;
    int status;
    if(argc!=3){
       printf("Usage Format: ./server -p <PortNumber>\n");
       printf("Sample Run: ./server -p 2000\n");
       exit(1);
    }
    port_no = atoi(argv[argc-1]);
    printf("Server running at port #%d\n", port_no);

    // Create server socket.
    if ( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
        fprintf(stderr, "Cannot create server socket! errno %i: %s\n",errno,strerror(errno));
        exit(1);
    }
    printf("Server socket created\n");
    // Bind (attach) this process to the server socket.
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(port_no);
    errno = bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
    if(errno < 0){
        printf("Server bind failure errno %i: %s\n",errno,strerror(errno));
        exit(1);
    }
    printf("Server socket is bound to port #%d\n", port_no);
    // Turn 'listenfd' to a listening socket. Listen queue size is 1.
    errno=listen(listenfd,listen_queue_size);
    if(errno < 0){
        printf("Server listen failure errno %i: %s\n",errno,strerror(errno));
        exit(1);
    }
    printf("Server listening with a queue of size %d. \n", listen_queue_size);
    // Wait for connection(s) from client(s).
    while (1){
        clientaddrlen = sizeof(clientaddr);
        connectfd = accept(listenfd, (struct sockaddr *) &clientaddr, &clientaddrlen);
        if(connectfd<0 br="">            printf("Server accept failure errno %d: %s\n",errno,strerror(errno));
            exit(1);
        }
        printf("A connection received from a client. Creating a child to serve the client.\n");
        if((childpid = fork()) == 0) { /* child process */
           close(listenfd); /* close listening socket */
           printf("Child process serving the client.\n");
           if (recv(connectfd, buffer, sizeof(buffer), 0 ) > 0){
               printf("Received message: %s\n", buffer);
           }
        close(connectfd);   /* parent closes connected socket */
        exit(1);
        }
        else if (childpid <0 br="" failed="" fork="" to="">             printf("Failed to fork\n");    
             printf("Fork error errno %d: %s\n",errno,strerror(errno));
        }
        else if(childpid != 0){  /* parent process */
             close(connectfd);   /* parent closes connected socket */  
             childpid = wait(&status);  
        }
    }
    return 0;
}

In order to avoid zombie processes created in the system, wait() function is used in the server main function.

Sample run can be created as follows:

1-)Create server and client executables :

$ cc -o server server_source.c
$ cc -o client client_source.c

2-)Run server at the same tab

$ ./server -p 2000

3-)Open a new tab, run client

$ ./client -a 127.0.0.1 -p 2000

You can get client_source.c and server_source.c files from the links.Application tested on ubuntu9.04.

Thursday, May 14, 2009

Ruby on Rails MySql Connection

After creating a new ROR application by typing

>rails applicationName

command from the console, Rails creates all the required files for the newly created application.

Rails creates many folders and database related files are placed under /config folder.

It is required to add some connection info into the database.yml file which is also located under /config folder of your new Rails project.

Rails keeps database-login related data out of the application code and places that login information into database.yml file.

database.yml file contains information about database connections. That file has 3 sections for development-test-production databases.

development:
  adapter: mysql
  encoding: utf8
  reconnect: false
  database: store_development
  pool: 5
  username: user
  password: userpass
  socket: /var/run/mysqld/mysqld.sock
test:
  adapter: mysql
  encoding: utf8
  reconnect: false
  database: store_test
  pool: 5
  username: user
  password: userpass
  socket: /var/run/mysqld/mysqld.sock
production:
  adapter: mysql
  encoding: utf8
  reconnect: false
  database: store_production
  pool: 5
  username: user
  password: userpass
  socket: /var/run/mysqld/mysqld.sock

adapter: section tells Rails what kind of database you are using.
database: name of the database that you want to connect to.
username&password: let's your application to login to the database.

You need to have that specified database created previously in your DBMS for connection.

For this example store_development database needs to be created previously in your mysql rdbms.

In order to create your database tables which are corresponding to models created use Rake.Rake helps to apply the migration to your database. You tell the rake to do some task and that task gets done.

>rake db:migrate

Rake looks for all the migrations not applied to the database and applies them. When it is required to add a new column to a database table, you can also use migration.

This helps you to remember what each migration does when you come back to your application at a later time.

You can create a migration explicitly by typing the command:

>ruby script/generate migration add_address

To be able to run migrations on Ubuntu 9.04 OS, also install required libmysql-ruby module.

Monday, May 4, 2009

Create Function PL/Sql

Function returns a value to the caller.

As a procedure, a function has two parts: the specification and the body.

Implementation is placed in the body part.

The following statement creates the function get_app_rec. This is the body of the function.
  FUNCTION get_app_rec
  (p_app_no  IN  appointment.app_no%TYPE)
  RETURN appointment%ROWTYPE
   IS
      v_rec                  appointment%ROWTYPE;
   BEGIN
      SELECT *
        INTO v_rec
        FROM appointment
       WHERE app_no = p_app_no
      ;
      RETURN v_rec;
   END;

Spec of the function is :
   FUNCTION get_app_rec
      (p_app_no  IN  appointment.app_no%TYPE)
   RETURN appointment%ROWTYPE;

Create Procedure PL/Sql

Procedure does not return a value to the caller.

Usually insert/update/delete operations are placed in a procedure.

A procedure has two parts: the specification and the body. Implementation is placed in the body part.

The following statement creates the procedure insert_visit_log. This is the body of the procedure.

  PROCEDURE insert_visit_log
      (p_visit_no  IN  visit_log.visit_no%TYPE,
       p_aim_code  IN  visit_log.aim_code%TYPE,
       p_op_name   IN  visit_log.op_name%TYPE,
       p_date      IN  visit_log.v_date%TYPE)
   IS
   BEGIN
      INSERT INTO visit_log
             (visit_no,aim_code,op_name,v_date)
      VALUES (p_visit_no, p_aim_code,p_op_name,p_date)
      ;
   END;

Spec of the procedure is :



  PROCEDURE insert_visit_log
      (p_visit_no  IN  visit_log.visit_no%TYPE,
       p_aim_code  IN  visit_log.aim_code%TYPE,
       p_op_name   IN  visit_log.op_name%TYPE,
       p_date      IN  visit_log.v_date%TYPE);

Create Sequence Pl/Sql

Sequence is usually used to generate unique primary key values for a relational database table.

Because a sequence is an independent db object, it is created and used independent of a database table.

Same sequence can be used for different tables.

The following statement creates the sequence visitor_seq.
CREATE SEQUENCE VISITOR_SEQ
  INCREMENT BY 1
  START WITH 1
  MINVALUE 1
  MAXVALUE 9999999999
  NOCYCLE
  NOORDER
  ; 

In order to drop previously created sequence issue following pl/sql statement.


DROP SEQUENCE VISITOR_SEQ;