Trouble reading data from server

Hi guys, i am currently having trouble reading multiple values from a server.
This is a client/server program.
User is supposed to key in the country name in the client and then server will return the capital of the country and its currency.
I successfully key-ed in the first input example China, the server returns the correct data. However, when i key-ed in subsequent values as Singapore. They returned nothing. Hope you guys can tell me what`s wrong with the code. The server is supposed to return the capital and currency of the country that is key-ed in.

Below are my codes for the server and client. Sorry, they are a little long but i guess its better that i give you guys the full picture

server.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>       /* for sockaddr_un struct */
#include <string.h>
#include "country.h"
#define DEFAULT_PROTOCOL   0

/* POSIX renames "Unix domain" as "local IPC."
    Not all systems define AF_LOCAL and PF_LOCAL (yet). */
#ifndef AF_LOCAL
#define AF_LOCAL    AF_UNIX
#endif
#ifndef PF_LOCAL
#define PF_LOCAL    PF_UNIX
#endif


/****************************************************************/
 int main  ()
  {

    
    int serverFd, clientFd, serverLen, clientLen;
    struct sockaddr_un serverAddress;/* Server address */
    struct sockaddr_un clientAddress; /* Client address */
    struct sockaddr* serverSockAddrPtr; /* Ptr to server address */
    struct sockaddr* clientSockAddrPtr; /* Ptr to client address */

    /* Ignore death-of-child signals to prevent zombies */
    signal (SIGCHLD, SIG_IGN);

    serverSockAddrPtr = (struct sockaddr*) &serverAddress;
    serverLen = sizeof (serverAddress);

    clientSockAddrPtr = (struct sockaddr*) &clientAddress;
    clientLen = sizeof (clientAddress);

    /* Create a socket, bidirectional, default protocol */
    serverFd = socket (AF_LOCAL, SOCK_STREAM, DEFAULT_PROTOCOL);
    serverAddress.sun_family = AF_LOCAL; /* Set domain type */
    strcpy (serverAddress.sun_path, "country"); /* Set name */
    
    unlink ("country"); /* Remove file if it already exists */
    
    bind (serverFd, serverSockAddrPtr, serverLen); /* Create file */ 
    listen (serverFd, 5); /* Maximum pending connection length */

    
    printf ("%s \n", "Starting Country Server");
    printf ("%s \n", " ");

    while (1) /* Loop forever */
      {
        /* Accept a client connection */
        clientFd = accept (serverFd, clientSockAddrPtr, &clientLen);

        if (fork () == 0) /* Create child to send recipe */
          {
            //writeCountryData (clientFd); /* Send the recipe */
	   while(1)
	   {
	    readCountry (clientFd);
            close (clientFd); /* Close the socket */
	    
            exit (/* EXIT_SUCCESS */ 0); /* Terminate */
          }
        else
          close (clientFd); /* Close the client descriptor */
      }
   
	return 0;
   }

   /****************************************************************/

 readCountry (int fd)
 {
   
   	readData();
	char capital[100]="", currencyCode[100]="", *p;
        char userInput[200];

        read(fd, userInput, 200);

	if ((p = strchr(userInput, '\n')) != NULL) /* to remove the [enter] from userinput */
      	*p = '\0';

	strcat(capital,userInput) ;
	strcat(capital," Capital       : ") ;
	strcat(capital,getCapital (userInput));
	
	write (fd, capital, strlen (capital) + 1);
	strcat(currencyCode,userInput) ;
	strcat(currencyCode," Currency Code       : ") ;
	strcat(currencyCode,getCurrencyCode (userInput));
	write (fd, currencyCode, strlen (currencyCode) + 1);
    
	
 }

readLine (int fd, char* str)
 {
   int n;
   do /* Read characters until NULL or end-of-input */
     {
	 // ssize_t read (int fd, void *buf, size_t count);
	 // if successful, read will:
	 // a) stores data read into 'buf', and
	 // b) returns the no. of bytes read
	 // read returns zero if it reaches end-of-input
       n = read (fd, str, 1); /* Read one character */
     }
   while (n > 0 && *str++ != 0);
   return (n > 0); /* Return false if end-of-input */
 }





}




client.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>            /* for sockaddr_un struct*/

#define DEFAULT_PROTOCOL    0

/* POSIX renames "Unix domain" as "local IPC."
    Not all systems define AF_LOCAL and PF_LOCAL (yet). */
#ifndef AF_LOCAL
#define AF_LOCAL    AF_UNIX
#endif
#ifndef PF_LOCAL
#define PF_LOCAL    PF_UNIX
#endif

/****************************************************************/
 main  ()
 {
   int clientFd, serverLen, result;
   struct sockaddr_un serverAddress;
   struct sockaddr* serverSockAddrPtr;
   serverSockAddrPtr = (struct sockaddr*) &serverAddress;
   serverLen = sizeof (serverAddress);

   /* Create a socket, bidirectional, default protocol */
   clientFd = socket (AF_LOCAL, SOCK_STREAM, DEFAULT_PROTOCOL);
   serverAddress.sun_family = AF_LOCAL; /* Server domain */
   strcpy (serverAddress.sun_path, "country"); /* Server name */
   do /* Loop until a connection is made with the server */
     {
       result = connect (clientFd, serverSockAddrPtr, serverLen);
       if (result == -1) sleep (1); /* Wait and then try again */
     }
   while (result == -1);
   
    while (1)
    {
	char country[300];
	printf("To end program, type 'end' \n");
	printf("Please enter country name >");
	fgets(country,sizeof(country),stdin);
	if (strcmp(country,"end\n") == 0)
	{
	    printf("Thank you for using country services\n");
	    break;

	}
	else 
	write(clientFd,country,strlen(country));
	readCountry(clientFd);
	close(clientFd);


    }
   
   
    /* Read the recipe */
   
    /* Close the socket */
   exit (/* EXIT_SUCCESS */ 0); /* Done */


   

 }
 /**************************************************************/

 readCountry(int fd)
 {
   char str[300];

   while (readLine (fd, str)) /* Read lines until end-of-input */
     printf ("%s\n", str); /* Echo line from socket */
 }

 /**************************************************************/

 /* Read a single NULL-terminated line */
 readLine (int fd, char* str)
 {
   int n;
   do /* Read characters until NULL or end-of-input */
     {
	 // ssize_t read (int fd, void *buf, size_t count);
	 // if successful, read will:
	 // a) stores data read into 'buf', and
	 // b) returns the no. of bytes read
	 // read returns zero if it reaches end-of-input
       n = read (fd, str, 1); /* Read one character */
     }
   while (n > 0 && *str++ != 0);
   return (n > 0); /* Return false if end-of-input */
 }

  writeUserInput(int fd)
  {
  
   char text[20];
   printf("To end program, type 'end' \n\n\n");
   printf("Please enter Country > ");
   fgets (text, sizeof(text), stdin);

   
   
   write (fd, text, strlen (text) + 1);
   
  }
  
Server Comments
You need to set the socket size each time.
1
2
3
        /* Accept a client connection */
        clientLen = sizeof (clientAddress);    // this line was missing
        clientFd = accept (serverFd, clientSockAddrPtr, &clientLen);
In fact, if you declare variables where they're used, then RAII removes this class of problem.

EDIT: I've just noticed this is C and not C++, so forget the RAII comment, but the size does need to be set.

You should be using sizeof in:
1
2
3
        char userInput[200];

        read(fd, userInput, 200);


And strncat should be used in:
1
2
3
4
	char capital[100]="", currencyCode[100]="", *p;
        //...
	strcat(capital,userInput) ;
	strcat(capital," Capital       : ") ;
and the same for currencyCode.

You don't actually need the fork(), it can all be done in one thread/process.

Client Comments
The code is:
1
2
3
4
5
6
7
   connect to server

   while (true)
       get input
       send request
       read reply
       close connection to server

Clearly, once the connection is closed, the conversation is over, right?
Last edited on
I have tried to edit the code as suggested by you. But it will still send a one result back and the loops terminates.
I am still very lost at the client side of coding.

my client code is now


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
while (1)
    {
	char country[300];
	printf("To end program, type 'end' \n");
	printf("Please enter country name >");
	fgets(country,sizeof(country),stdin);
	if (strcmp(country,"end\n") == 0)
	{
	    printf("Thank you for using country services\n");
	    close(clientFd);
	    break;

	}
	else 
	{
	write(clientFd,country,strlen(country));
	readCountry(clientFd);
	
	}

    }
   
   
    /* Read the recipe */
   close(clientFd);
    /* Close the socket */
   exit (/* EXIT_SUCCESS */ 0); /* Done */


And in regards to the fork(), i am supposed to use it as it is a requirement of my assignment.
For the client side, i am supposed to exit the program when the user keys in enter so i changed the placement of close(clientFd) into the if statement.
However, the result is still the same. Really lost on this matter
The server just handles one request then terminates, so the client must do the same.

If you want the client to send multiple requests and the server to handle multiple requests, you must decide exactly what is to be sent/received and when, that is define your own protocol.
Last edited on
Thanks for your help! I solved it, it was due to the placement of the code.
I forgot to close the serverFd in the server side before opening another socket. That is why i kept getting one output
Topic archived. No new replies allowed.