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.

No comments:

Post a Comment