【问题标题】:How do I return a string from server to client in C?如何在C中将字符串从服务器返回到客户端?
【发布时间】:2018-03-17 21:12:14
【问题描述】:

我需要向客户发送一个字符串,其中包括车辆成本和带有修饰符(carStyling)的车辆。我想向客户返回一个包含斜线和成本的字符串。类似的东西;

您的 Sedan Offroad 将花费 150000 美元。

下面的段落包含必要的代码。

#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

    }

  }

}

这里的另一个是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;

}

所以,如果有人知道如何同时发回字符串和成本。请回复。谢谢。

【问题讨论】:

  • 由于使用了 C++ 结构,它无法编译为 C。你为什么给它贴上标签?另外:你的问题到底是什么? “X怎么办?”似乎太宽泛了。
  • 虽然将代码分成带有单个空行的段落有助于提高可读性,但您可能在另一个方向上走得太远了。您显示的代码是否真的正确复制粘贴?
  • 我想说的是,所有这些空行使代码更难阅读,更难理解正在发生的事情,并使我们滚动的次数超出了需要(获得概览从来都不是一件好事)。
  • 请格式化您的代码,以便缩进正确,并且在每个非空行之后都没有空行。
  • @ThadoeHtut 怎么可能两者兼有?如果您的代码使用 C 编译器编译,则为 C,而如果使用 C++ 编译器编译,则为 C++。既然您的代码无法在 C 编译器中编译,正如我之前所介绍的,您为什么要用 C 标记您的问题?

标签: c++ c port stringstream


【解决方案1】:

您可以通过复制字节将 std::string sline 打包到发送缓冲区中:

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

发送,然后在客户端以同样的方式解压。

编辑: 为您的服务器尝试下面的代码,这是您想要的吗?

#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 
    } 
  } 
}

【讨论】:

  • sline.length() 的长度可用时,为什么还要使用strlen?无论如何都不需要这个额外的memcpy,因为您可以直接在对send 的调用中使用sline.c_str()
  • 你是对的,但是如果他想将“字符串和成本”作为一个发送。也许最好的方法是找出一些发送协议。例如打包到传入字符串的缓冲区长度,然后是字符串,然后是四个字节 int 作为成本。然后在另一边打开包装。
  • @PawełDymowski 它编译得很好,但并没有真正打印出我想要的东西。只返回我写的任何内容的大写字母。
  • @ThadoeHtut 大写因为你有: // 将行转换为大写。 for (i = 0; line[i] != '\0'; i++) line[i] = toupper(line[i]);
  • @ThadoeHtut 如果您想将成本发送给客户,您也需要将其 memcopy 到 sendung 缓冲区。
猜你喜欢
  • 2017-10-21
  • 1970-01-01
  • 2016-06-12
  • 1970-01-01
  • 2018-03-02
  • 1970-01-01
  • 2012-06-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多