-3

I need to send a string back to client that includes the cost of vehicle and the vehicle with modifier(carStyling). I want to return a string containing the sline and the cost to the client. Something like;

Your Sedan Offroad will cost $150000.

Paragraph below contains the code necessary.

#include <arpa/inet.h>

#include <netdb.h>

#include <netinet/in.h>

#include <unistd.h>

#include <iostream>

#include <cstring>

#include <stdlib.h>

#include <stdio.h>

#include <string>

#include <sstream>



#define MAX_MSG 100

#define LINE_ARRAY_SIZE (MAX_MSG+1)



using namespace std;



int main()

{

  int listenSocket, connectSocket, i;

  unsigned short int listenPort;

  socklen_t clientAddressLength
;

  struct sockaddr_in clientAddress, serverAddress;

  char line[LINE_ARRAY_SIZE];





  cout << "Enter port number to listen on (between 1500 and 65000): ";

  cin >> listenPort;



  // Create socket for listening for client connection

  // requests.

  listenSocket = socket(AF_INET, SOCK_STREAM, 0);

  if (listenSocket < 0) {

    cerr << "cannot create listen socket";

    exit(1);

  }



  // Bind listen socket to listen port. First set various

  // fields in the serverAddress structure, then call

  // bind().



  // htonl() and htons() convert long integers and short

  // integers (respectively) from host byte order (on x86

  // this is Least Significant Byte first) to network byte

  // order (Most Significant Byte first).

  serverAddress.sin_family = AF_INET;

  serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);

  serverAddress.sin_port = htons(listenPort);



  if (bind(listenSocket,

           (struct sockaddr *) &serverAddress,

           sizeof(serverAddress)) < 0) {

    cerr << "cannot bind socket";

    exit(1);

  }



  // Wait for connections from clients. This is a

  // non-blocking call; i.e., it registers this program with

  // the system as expecting connections on this socket, and

  // then this thread of execution continues on.

  listen(listenSocket, 5);



  while (1) {

    cout << "Waiting for TCP connection on port " << listenPort << " ...\n";



    // Accept a connection with a client that is requesting

    // one. The accept() call is a blocking call; i.e., this

    // thread of execution stops until a connection comes

    // in. connectSocket is a new socket that the system

    // provides, separate from listenSocket. We *could*

    // accept more connections on listenSocket, before

    // connectSocket is closed, but this program doesn't do

    // that.

    clientAddressLength = sizeof(clientAddress);

    connectSocket = accept(listenSocket,

                           (struct sockaddr *) &clientAddress,

                           &clientAddressLength);

    if (connectSocket < 0) {

      cerr << "cannot accept connection ";

      exit(1);

    }



    // Show the IP address of the client.

    // inet_ntoa() converts an IP address from binary form to the

    // standard "numbers and dots" notation.

    cout << "  connected to " << inet_ntoa(clientAddress.sin_addr);



    // Show the client's port number.

    // ntohs() converts a short int from network byte order (which is

    // Most Significant Byte first) to host byte order (which on x86,

    // for example, is Least Significant Byte first).

    cout << ":" << ntohs(clientAddress.sin_port) << "\n";



    // Read lines from socket, using recv(), storing them in the line

    // array.  If no messages are currently available, recv() blocks

    // until one arrives.

    // First set line to all zeroes, so we'll know where the end of

    // the string is.

    memset(line, 0x0, LINE_ARRAY_SIZE);



    while (recv(connectSocket, line, MAX_MSG, 0) > 0) {

      cout << "  --  " << line << "\n";



      // Convert line to upper case.

      for (i = 0; line[i] != '\0'; i++)

        line[i] = toupper(line[i]);





      // creating an object to direct line to a string array

      std::string delimiter[2];

      int i = 0;

      double cost = 0;

      std::string carType;

      std::string carStyling;

      std::string sline;

      sline = line;

      stringstream ssin(sline);



          while (ssin.good() && i < 2){

            ssin >> delimiter[i];

            ++i;

      }

          for(i = 0; i < 2; i++){

            cout << delimiter[i] << endl;

      }



          if(i==0) {

            carType = delimiter[0];



              if(carType.compare("SEDAN")==0){

                sline = "Your Sedan";

                cost = 100000;

                std::copy(sline.begin(), sline.end(), line);

                line[sline.size()] = '\0';

              }

              else if(carType.compare("MPV")==0){

                sline = "MPV";

                cost = 120000;

                std::copy(sline.begin(), sline.end(), line);

                line[sline.size()] = '\0';

              }

              else if(carType.compare("SUV")==0){

                sline = "SUV";

                cost = 140000;

                std::copy(sline.begin(), sline.end(), line);

                line[sline.size()] = '\0';

              }

              else if(carType.compare("LUXURY")==0){

                sline = "LUXURY";

                cost = 180000;

                std::copy(sline.begin(), sline.end(), line);

                line[sline.size()] = '\0';

              }



         if(i==2) {

            carStyling = delimiter[1];



              if(carStyling.compare("SPORTY")==0){

                sline += "Sporty";

                cost = cost * 1.5;

              }

              else if(carStyling.compare("OFFROAD")==0){

                sline += "Offroad";

                cost = cost * 1.3;

              }



        }



      }





      // Send converted line back to client.

      if (send(connectSocket, line, strlen(line) + 1, 0) < 0)

        cerr << "Error: cannot send modified data";



      memset(line, 0x0, LINE_ARRAY_SIZE);  // set line to all zeroes

    }

  }

}

The other one here is the code for the client.cc

#include <netdb.h>

#include <netinet/in.h>

#include <unistd.h>

#include <iostream>

#include <cstring>

#include <stdlib.h>



#define MAX_LINE 100

#define LINE_ARRAY_SIZE (MAX_LINE+1)



using namespace std;



int main()

{

  int socketDescriptor;

  unsigned short int serverPort;

  struct sockaddr_in serverAddress;

  struct hostent *hostInfo;

  char buf[LINE_ARRAY_SIZE], c;



  cout << "Enter server host name or IP address: ";

  cin.get(buf, MAX_LINE, '\n');



  // gethostbyname() takes a host name or ip address in "numbers and

  // dots" notation, and returns a pointer to a hostent structure,

  // which we'll need later.  It's not important for us what this

  // structure is actually composed of.

  hostInfo = gethostbyname(buf);

  if (hostInfo == NULL) {

    cout << "problem interpreting host: " << buf << "\n";

    exit(1);

  }



  cout << "Enter server port number: ";

  cin >> serverPort;

  cin.get(c); // dispose of the newline



  // Create a socket.  "AF_INET" means it will use the IPv4 protocol.

  // "SOCK_STREAM" means it will be a reliable connection (i.e., TCP;

  // for UDP use SOCK_DGRAM), and I'm not sure what the 0 for the last

  // parameter means, but it seems to work.

  socketDescriptor = socket(AF_INET, SOCK_STREAM, 0);

  if (socketDescriptor < 0) {

    cerr << "cannot create socket\n";

    exit(1);

  }



  // Connect to server.  First we have to set some fields in the

  // serverAddress structure.  The system will assign me an arbitrary

  // local port that is not in use.

  serverAddress.sin_family = hostInfo->h_addrtype;

  memcpy((char *) &serverAddress.sin_addr.s_addr,

         hostInfo->h_addr_list[0], hostInfo->h_length);

  serverAddress.sin_port = htons(serverPort);



  if (connect(socketDescriptor,

              (struct sockaddr *) &serverAddress,

              sizeof(serverAddress)) < 0) {

    cerr << "cannot connect\n";

    exit(1);

  }



  cout << "\nWelcome to Car Customization Server. What are your orders?\n";

  cout << ">> Type of vehicle: Sedan, MPV, SUV, Luxury\n";

  cout << ">> Type of Styling: Sporty, Offroad\n";

  cout << ">> Eg. To order type: MPV Sporty\n";



  // Prompt the user for input, then read in the input, up to MAX_LINE

  // charactars, and then dispose of the rest of the line, including

  // the newline character.

  cout << "Enter Order: ";

  cin.get(buf, MAX_LINE, '\n');

  while (cin.get(c) && c != '\n') 

    ; //Loop does nothing except consume the spare bytes





  // Stop when the user inputs a line with just a dot.

  while (strcmp(buf, ".")) { //strcmp returns 0 when the two strings

                 //are the same, so this continues when

                 //they are different

    // Send the line to the server.

    if (send(socketDescriptor, buf, strlen(buf) + 1, 0) < 0) {

      cerr << "cannot send data ";

      close(socketDescriptor); //Note this is just like using files...

      exit(1);

    }



    // Zero out the buffer.

    memset(buf, 0x0, LINE_ARRAY_SIZE);



    // Read the modified line back from the server.

    if (recv(socketDescriptor, buf, MAX_LINE, 0) < 0) {

      cerr << "didn't get response from server?";

      close(socketDescriptor);

      exit(1);

    }



    cout << "results: " << buf << "\n";



    // Prompt the user for input, then read in the input, up to MAX_LINE

    // charactars, and then dispose of the rest of the line, including

    // the newline character.  As above.

    cout << "Enter Order: ";

    cin.get(buf, MAX_LINE, '\n');

    while (cin.get(c) && c != '\n')

      ; //again, consuming spare bytes

  }



  close(socketDescriptor);

  return 0;

}

So there, if anyone knows how to send back both the string and the cost. Please reply. Thank you.

  • 1
    It fails to compile as C, due to the use of C++ constructs. Why did you tag it? In addition: what, exactly, is your question? "how to do X?" Seems too broad. – Algirdas Preidžius Oct 06 '17 at 06:14
  • 4
    While it's good for readability to separate code into paragraphs with a single empty lines, you have gone maybe a bit to far in the other direction. Is the code you show really copy-pasted properly? – Some programmer dude Oct 06 '17 at 06:16
  • @AlgirdasPreidžius It's a combination of both. – Thadoe Htut Oct 06 '17 at 06:32
  • @Someprogrammerdude I'm sure it is. The only thing missing is another file containing the client but that's not necessary. – Thadoe Htut Oct 06 '17 at 06:33
  • What is a combination of what? – n. m. could be an AI Oct 06 '17 at 06:41
  • 1
    What I'm trying to say is that all those empty lines makes the code *harder* to read, harder to follow what's going on, and make us scroll much more than needed (which is never a good thing to get an overview). – Some programmer dude Oct 06 '17 at 06:41
  • 1
    Please format your code so that indentation is proper and there is no empty line after every single non-empty one. – n. m. could be an AI Oct 06 '17 at 06:41
  • As for your problem, why don't you simply format the string on the sending side, and send the whole string? – Some programmer dude Oct 06 '17 at 06:42
  • 1
    @ThadoeHtut How can it be both? If your code is compiled with C compiler, it's C, while if it is compiled with C++ compiler - it's C++. Since your code wouldn't compile in C compiler, as I've covered before, why did you tag your question with C? – Algirdas Preidžius Oct 06 '17 at 12:22
  • It compiles in C++. Yes, but the code uses both C and C++. – Thadoe Htut Oct 07 '17 at 04:50
  • @ThadoeHtut Unless your compiles as C, it doesn't "use C", it instead is C++, which in many ways is similar to C. Please remove the C tag, as your code **is not** C code and doesn't compile as such. – tambre Oct 07 '17 at 12:19
  • [`using namespace std;` is a bad practice](https://stackoverflow.com/q/1452721/2176813), never use it. In C++ headers such as `stdio.h` and `stdlib.h` are [deprecated C-compatibility headers](http://en.cppreference.com/w/cpp/header#C_compatibility_headers) - use `cstdio` and `cstdlib` instead. – tambre Oct 07 '17 at 12:21

1 Answers1

0

You can pack your std::string sline into sending buffer by copying bytes:

memcpy(line, sline.c_str(), strlen(sline.c_str()))

send it, and then on the client side unpack it the same way.

edit: Try code below for you server, is this what you wanted?

#include <arpa/inet.h> 
#include <netdb.h> 
#include <netinet/in.h> 
#include <unistd.h> 
#include <iostream> 
#include <cstring> 
#include <stdlib.h> 
#include <stdio.h> 
#include <string> 
#include <sstream> 

#define MAX_MSG 100 
#define LINE_ARRAY_SIZE (MAX_MSG+1) 

using namespace std; 

int main() 
{ 
  int listenSocket, connectSocket, i; 
  unsigned short int listenPort; 
  socklen_t clientAddressLength; 
  struct sockaddr_in clientAddress, serverAddress; 
  char line[LINE_ARRAY_SIZE]; 

  cout << "Enter port number to listen on (between 1500 and 65000): "; 
  cin >> listenPort; 

  listenSocket = socket(AF_INET, SOCK_STREAM, 0); 

  if (listenSocket < 0) { 
    cerr << "cannot create listen socket"; 
    exit(1); 
  } 

  serverAddress.sin_family = AF_INET; 
  serverAddress.sin_addr.s_addr = htonl(INADDR_ANY); 
  serverAddress.sin_port = htons(listenPort); 

  if (bind(listenSocket, (struct sockaddr *) &serverAddress, 
           sizeof(serverAddress)) < 0) { 
    cerr << "cannot bind socket"; 
    exit(1); 
  } 

  listen(listenSocket, 5); 

  while (1) { 
    cout << "Waiting for TCP connection on port " << listenPort << " ...\n"; 
    clientAddressLength = sizeof(clientAddress); 
    connectSocket = accept(listenSocket, (struct sockaddr *) &clientAddress, 
                           &clientAddressLength); 

    if (connectSocket < 0) { 
      cerr << "cannot accept connection "; 
      exit(1); 
    } 
    cout << "  connected to " << inet_ntoa(clientAddress.sin_addr); 
    cout << ":" << ntohs(clientAddress.sin_port) << "\n"; 

    memset(line, 0x0, LINE_ARRAY_SIZE); 
    while (recv(connectSocket,line, MAX_MSG, 0) > 0) { 

    cout << "  --  " << line << "\n"; 

    std::string delimiter[2]; 
    int i = 0; 
    double cost = 0; 
    std::string carType; 
    std::string carStyling; 
    std::string sline; 
    sline = line; 
    stringstream ssin(sline); 

    while (ssin.good() && i < 2){ 
      ssin >> delimiter[i]; 
      ++i; 
    } 
    sline = ""; 

    for(i = 0; i < 2; i++){ 
      cout << delimiter[i] << endl; 
    } 
    sline += "Your "; 
    carType = delimiter[0]; 

    if(carType.compare("Sedan")==0){ 
      sline += "Sedan"; 
      cost = 100000; 
    } 
    else if(carType.compare("MPV")==0){ 
      sline += "MPV"; 
      cost = 120000; 
    } 
    else if(carType.compare("SUV")==0){ 
      sline += "SUV"; 
      cost = 140000; 
    } 
    else if(carType.compare("Luxury")==0){ 
      sline += "Luxury"; 
      cost = 180000; 
    } 

    carStyling = delimiter[1]; 

    if(carStyling.compare("Sporty")==0){ 
      sline += " Sporty "; 
      cost = cost * 1.5; 
    } 

    else if(carStyling.compare("Offroad")==0){ 
      sline += " Offroad "; 
      cost = cost * 1.3; 
    } 

    sline += "will cost "; 
    std::ostringstream ss; 
    ss << cost; 
    sline += ss.str(); 

    sline.copy(line, sline.length()); 

    if (send(connectSocket, line, strlen(line) + 1, 0) < 0) 
      cerr << "Error: cannot send modified data"; 
      memset(line, 0x0, LINE_ARRAY_SIZE);  // set line to all zeroes 
    } 
  } 
}
Paweł Dymowski
  • 840
  • 7
  • 14
  • 2
    Why use `strlen` when the length is available with `sline.length()`? And this extra `memcpy` is not needed anyway, since you can use `sline.c_str()` directly in the call to `send`. – Some programmer dude Oct 06 '17 at 06:37
  • You are right, but if he want to send "both the string and the cost" as one. Maybe the best way will be to figure out some sending protocol. For example pack to buffer length of incoming string, then string, then four bytes int for cost. Then unpack it on the other side. – Paweł Dymowski Oct 06 '17 at 06:47
  • @PawełDymowski It compiles well, but doesn't really print what i wanted. Just returns the uppercase letters of whatever i wrote. – Thadoe Htut Oct 07 '17 at 15:04
  • @ThadoeHtut uppercase becaues you have: // Convert line to upper case. for (i = 0; line[i] != '\0'; i++) line[i] = toupper(line[i]); – Paweł Dymowski Oct 07 '17 at 16:09
  • @ThadoeHtut If you want to send cost to the client you need to memcopy it to the sendung buffer too. – Paweł Dymowski Oct 07 '17 at 16:25