Juraj
Juraj

Reputation: 75

Sending multiple messages over a TCP port

I have a program that creates a socket (server and client program) and sends a message via a TCP port using that socket. My question is, how can I exchange multiple messages? Every time I send a message the port gets closed and I need to use another port to send another message.

For example, I have to send 2 numbers from the client to the server and the server needs to reply back the total sum of the numbers I send. How would I achieve sending undefined number or even 2 numbers over the SAME port?

Here are the codes (pretty much standard stuff):

Server:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>

char* Itoa(int value, char* str, int radix) 
{
    static char dig[] =
      "0123456789"
      "abcdefghijklmnopqrstuvwxyz";
    int n = 0, neg = 0;
    unsigned int v;
    char* p, *q;
    char c;
    if (radix == 10 && value < 0) {
      value = -value;
      neg = 1;
    }
    v = value;
    do {
      str[n++] = dig[v%radix];
      v /= radix;
    } while (v);
    if (neg)
      str[n++] = '-';
    str[n] = '\0';
    for (p = str, q = p + (n-1); p < q; ++p, --q)
      c = *p, *p = *q, *q = c;
    return str;
}

void error (const char *msg)
{
    perror (msg);
    exit (1);
}
int main (int argc, char *argv[])
{
    if (argc < 2)
    {
        fprintf (stderr, "ERROR, no port provided\n");
        exit (1);
    }
    //nova varijabla za sumiranje primljenih brojeva
    int suma=0;

    int sockfd, newsockfd, portno,i;
    socklen_t clilen;
    char buffer[256];
    struct sockaddr_in serv_addr, cli_addr;
    int n;
    for (i=0;i<2;i++)
    {
        sockfd = socket (AF_INET, SOCK_STREAM, 0);
        if (sockfd < 0) error ("ERROR opening socket");
        memset ((char *) &serv_addr, 0, sizeof (serv_addr));
        portno = atoi (argv[1]);
        portno+=i;
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_addr.s_addr = INADDR_ANY;
        serv_addr.sin_port = htons (portno);
        if (bind (sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0) error ("ERROR on binding");
        //test za ispis otvorenog porta
        printf("Uspjesno otvoren localhost na portu %d\n", portno); 
        listen (sockfd, 5);
        clilen = sizeof (cli_addr);
        newsockfd = accept (sockfd, (struct sockaddr *) &cli_addr, &clilen);
        if (newsockfd < 0) error ("ERROR on accept");
        memset (buffer, 0, 256);
        n = read (newsockfd, buffer, 255);
        if (n < 0) error ("ERROR reading from socket");
        printf ("%d. proslan broj: %s\n", i+1, buffer);
//print
        suma=suma+atoi(buffer);
//radi!!        printf("suma je %d\n", suma);
//od klijenta: n = write (sockfd, buffer, strlen (buffer));
//char *  itoa ( int value, char * str, int base );
        Itoa(suma, buffer, 10);
        n = write (newsockfd, buffer, strlen(buffer));
        if (n < 0) error ("ERROR writing to socket");
        close (newsockfd);
        close (sockfd);
    }
    return 0;
}

Client:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
void    error (const char *msg)
{
    perror (msg);
    exit (1);
}
int
main (int argc, char *argv[])
{
    if (argc < 3)
    {
        fprintf (stderr, "usage %s hostname port\n", argv[0]);
        exit (1);
    }
    int sockfd, portno, n,i;
    struct sockaddr_in serv_addr;
    struct hostent *server;
    char buffer[256];
    for (i=0;i<2;i++)
    {
        portno = atoi (argv[2]);
        sockfd = socket (AF_INET, SOCK_STREAM, 0);
        if (sockfd < 0)
        error ("Ne mogu otvoriti socket!");
        server = gethostbyname (argv[1]);
        if (server == NULL)
        {
            fprintf (stderr, "Greska, ne postoji!\n");
            exit (1);
        }
        memset ((char *) &serv_addr, 0, sizeof (serv_addr));
        serv_addr.sin_family = AF_INET;
        bcopy ((char *) server->h_addr,
        (char *) &serv_addr.sin_addr.s_addr,
        server->h_length);
        portno+=i;
        serv_addr.sin_port = htons (portno);
        if (connect (sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0)
        error ("ERROR connecting");
        printf ("%d. broj za slanje: ", i+1);
        memset (buffer, 0, 256);
        fgets (buffer, 255, stdin);
        n = write (sockfd, buffer, strlen (buffer));
        if (n < 0)
        error ("ERROR writing to socket");
        memset (buffer, 0, 256);
        n = read (sockfd, buffer, 255);
        if (n < 0)
        error ("ERROR reading from socket");
        if (i==1) printf ("Suma iznosi: %s\n", buffer);
        close (sockfd);
    }
    return 0;
}

So, for example, I run the code and get this for the server side:

j@PC ~/Desktop/Mreze/Lab1/rijeseno $ ./server2 5000
Uspjesno otvoren localhost na portu 5000
1. proslan broj: 45

Uspjesno otvoren localhost na portu 5001
2. proslan broj: 56

j@PC ~/Desktop/Mreze/Lab1/rijeseno $ 

And on the client side:

j@PC ~/Desktop/Mreze/Lab1/rijeseno $ ./client2 localhost 5000
1. broj za slanje: 45
2. broj za slanje: 56
Suma iznosi: 101

I've tried putting a while loop so it loops the part with sending but without success. Please explain to me where should I even put it so it works. Thank you!

Upvotes: 2

Views: 5442

Answers (2)

Valeri Atamaniouk
Valeri Atamaniouk

Reputation: 5163

Here is a problem:

n = read (newsockfd, buffer, 255);

What you do, is you perform read once, and the data might not be fully available. The fact is, you need to read data, as long as you received the data completely, or detected EOF condition (-1 return value).

Generally you need to write more reliable code for receiving part, as it is not guaranteed on stream protocol that your message boundaries are kept in any form.

Here is a (very unoptimal, yet simple) code for reading data:

int readLine(int fd, char data[])
{
   size_t len = 0;
   while (len < maxlen)
   {
      char c;
      int ret = read(fd, &c, 1);
      if (ret < 0)
      {
          data[len] = 0;
          return len; // EOF reached
      }
      if (c == '\n')
      {
          data[len] = 0;
          return len; // EOF reached
      }
      data[len++] = c;
   }
}

And usage example:

char buffer[256];
int num1, num2;

readLine(newsockfd, buffer);
num1 = atoi(buffer);
readLine(newsockfd, buffer);
num2 = atoi(buffer);

Upvotes: 2

Grijesh Chauhan
Grijesh Chauhan

Reputation: 58261

First Put your connection() function before and close() after for loop. Just for an idea

connect (sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)
for (i=0;i<n;i++){
 // do you introspection with server
 // actually send number to server 
}
// Code to read result: SUM from server
close (sockfd);

Upvotes: 1

Related Questions